【问题标题】:InputStream from a URL来自 URL 的 InputStream
【发布时间】:2011-10-19 10:18:10
【问题描述】:

如何从 URL 获取 InputStream?

例如,我想在 url wwww.somewebsite.com/a.txt 处获取文件,并通过 servlet 将其作为 Java 中的 InputStream 读取。

我试过了

InputStream is = new FileInputStream("wwww.somewebsite.com/a.txt");

但我得到的是一个错误:

java.io.FileNotFoundException

【问题讨论】:

标签: java url inputstream


【解决方案1】:

使用 java.net.URL#openStream() 和正确的 URL(包括协议!)。例如

InputStream input = new URL("http://www.somewebsite.com/a.txt").openStream();
// ...

另见:

【讨论】:

  • 您是否知道这是否会在每次读取 InputStream 时发出网络请求,或者是否一次读取整个文件以便不必在读取时发出网络请求?
  • 在 Android 的 UI 线程中调用此方法会引发异常。在后台线程中执行此操作。使用Bolts-Android
【解决方案2】:

试试:

final InputStream is = new URL("http://wwww.somewebsite.com/a.txt").openStream();

【讨论】:

    【解决方案3】:

    (a) wwww.somewebsite.com/a.txt 不是“文件 URL”。它根本不是一个 URL。如果您将http:// 放在它的前面,它将是一个HTTP URL,这显然是您想要的。

    (b)FileInputStream 用于文件,而不是 URL。

    (c) 从any URL 获取输入流的方法是通过URL.openStream(),URL.getConnection().getInputStream(),,这是等效的,但您可能有其他理由获取URLConnection 并使用先说吧。

    【讨论】:

      【解决方案4】:

      您的原始代码使用 FileInputStream,用于访问文件系统托管文件。

      您使用的构造函数将尝试在当前工作目录的 www.somewebsite.com 子文件夹中找到名为 a.txt 的文件(系统属性 user.dir 的值)。您提供的名称将使用 File 类解析为文件。

      URL 对象是解决这个问题的通用方法。您可以使用 URL 访问本地文件,也可以使用网络托管资源。 URL 类除了 http:// 或 https:// 之外还支持 file:// 协议,所以你很高兴。

      【讨论】:

        【解决方案5】:

        纯Java:

         urlToInputStream(url,httpHeaders);
        

        我使用这种方法取得了一些成功。它处理重定向,并且可以将可变数量的 HTTP 标头 传递为Map<String,String>。它还允许从 HTTP 重定向到 HTTPS

        private InputStream urlToInputStream(URL url, Map<String, String> args) {
            HttpURLConnection con = null;
            InputStream inputStream = null;
            try {
                con = (HttpURLConnection) url.openConnection();
                con.setConnectTimeout(15000);
                con.setReadTimeout(15000);
                if (args != null) {
                    for (Entry<String, String> e : args.entrySet()) {
                        con.setRequestProperty(e.getKey(), e.getValue());
                    }
                }
                con.connect();
                int responseCode = con.getResponseCode();
                /* By default the connection will follow redirects. The following
                 * block is only entered if the implementation of HttpURLConnection
                 * does not perform the redirect. The exact behavior depends to 
                 * the actual implementation (e.g. sun.net).
                 * !!! Attention: This block allows the connection to 
                 * switch protocols (e.g. HTTP to HTTPS), which is <b>not</b> 
                 * default behavior. See: https://stackoverflow.com/questions/1884230 
                 * for more info!!!
                 */
                if (responseCode < 400 && responseCode > 299) {
                    String redirectUrl = con.getHeaderField("Location");
                    try {
                        URL newUrl = new URL(redirectUrl);
                        return urlToInputStream(newUrl, args);
                    } catch (MalformedURLException e) {
                        URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
                        return urlToInputStream(newUrl, args);
                    }
                }
                /*!!!!!*/
        
                inputStream = con.getInputStream();
                return inputStream;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        

        完整的示例调用

        private InputStream getInputStreamFromUrl(URL url, String user, String passwd) throws IOException {
                String encoded = Base64.getEncoder().encodeToString((user + ":" + passwd).getBytes(StandardCharsets.UTF_8));
                Map<String,String> httpHeaders=new Map<>();
                httpHeaders.put("Accept", "application/json");
                httpHeaders.put("User-Agent", "myApplication");
                httpHeaders.put("Authorization", "Basic " + encoded);
                return urlToInputStream(url,httpHeaders);
            }
        

        【讨论】:

        • HttpURLConnection 已经遵循重定向,除非你告诉它不要这样做,而你没有这样做。
        • 我知道 OP 没有提到标题,但我很欣赏这个简洁(好吧,考虑到它是 Java)的例子。
        • @EJP 我添加了一些解释作为内联注释。我想,我主要介绍了 HTTP 301 将 HTTP 地址重定向到 HTTPS 地址的情况下的重定向块。当然,这超出了最初的问题,而是默认实现不处理的常见用例。见:stackoverflow.com/questions/1884230/…
        • 您的代码在没有重定向块的情况下同样有效,因为HttpURLConnection 默认情况下已经遵循重定向,正如我已经说过的那样。
        • @user207421 这部分正确。重定向块用于协议切换,例如 http->https,默认情况下不支持。我试图在代码注释中表达这一点。见stackoverflow.com/questions/1884230/…
        【解决方案6】:

        这是一个读取给定网页内容的完整示例。 该网页是从 HTML 表单中读取的。我们使用标准的InputStream 类,但使用 JSoup 库可以更轻松地完成。

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        
        </dependency>
        
        <dependency>
            <groupId>commons-validator</groupId>
            <artifactId>commons-validator</artifactId>
            <version>1.6</version>
        </dependency>  
        

        这些是 Maven 依赖项。我们使用 Apache Commons 库来验证 URL 字符串。

        package com.zetcode.web;
        
        import com.zetcode.service.WebPageReader;
        import java.io.IOException;
        import java.nio.charset.StandardCharsets;
        import javax.servlet.ServletException;
        import javax.servlet.ServletOutputStream;
        import javax.servlet.annotation.WebServlet;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        
        @WebServlet(name = "ReadWebPage", urlPatterns = {"/ReadWebPage"})
        public class ReadWebpage extends HttpServlet {
        
            @Override
            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws ServletException, IOException {
        
                response.setContentType("text/plain;charset=UTF-8");
        
                String page = request.getParameter("webpage");
        
                String content = new WebPageReader().setWebPageName(page).getWebPageContent();
        
                ServletOutputStream os = response.getOutputStream();
                os.write(content.getBytes(StandardCharsets.UTF_8));
            }
        }
        

        ReadWebPage servlet 读取给定网页的内容并以纯文本格式将其发送回客户端。阅读页面的任务委托给WebPageReader

        package com.zetcode.service;
        
        import java.io.BufferedReader;
        import java.io.IOException;
        import java.io.InputStream;
        import java.io.InputStreamReader;
        import java.net.URL;
        import java.nio.charset.StandardCharsets;
        import java.util.logging.Level;
        import java.util.logging.Logger;
        import java.util.stream.Collectors;
        import org.apache.commons.validator.routines.UrlValidator;
        
        public class WebPageReader {
        
            private String webpage;
            private String content;
        
            public WebPageReader setWebPageName(String name) {
        
                webpage = name;
                return this;
            }
        
            public String getWebPageContent() {
        
                try {
        
                    boolean valid = validateUrl(webpage);
        
                    if (!valid) {
        
                        content = "Invalid URL; use http(s)://www.example.com format";
                        return content;
                    }
        
                    URL url = new URL(webpage);
        
                    try (InputStream is = url.openStream();
                            BufferedReader br = new BufferedReader(
                                    new InputStreamReader(is, StandardCharsets.UTF_8))) {
        
                        content = br.lines().collect(
                              Collectors.joining(System.lineSeparator()));
                    }
        
                } catch (IOException ex) {
        
                    content = String.format("Cannot read webpage %s", ex);
                    Logger.getLogger(WebPageReader.class.getName()).log(Level.SEVERE, null, ex);
                }
        
                return content;
            }
        
            private boolean validateUrl(String webpage) {
        
                UrlValidator urlValidator = new UrlValidator();
        
                return urlValidator.isValid(webpage);
            }
        }
        

        WebPageReader 验证 URL 并读取网页内容。 它返回一个包含页面 HTML 代码的字符串。

        <!DOCTYPE html>
        <html>
            <head>
                <title>Home page</title>
                <meta charset="UTF-8">
            </head>
            <body>
                <form action="ReadWebPage">
        
                    <label for="page">Enter a web page name:</label>
                    <input  type="text" id="page" name="webpage">
        
                    <button type="submit">Submit</button>
        
                </form>
            </body>
        </html>
        

        最后,这是包含 HTML 表单的主页。 这取自我的tutorial 关于这个话题。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-02-28
          • 2012-01-07
          • 1970-01-01
          • 2017-01-28
          • 2011-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多