Java 从URL输入流

Java 从URL输入流,java,url,inputstream,Java,Url,Inputstream,如何从URL获取InputStream 例如,我想获取urlwwwww.somewebsite.com/a.txt上的文件,并通过servlet将其作为Java中的InputStream读取 我试过了 InputStream is = new FileInputStream("wwww.somewebsite.com/a.txt"); 但我得到的是一个错误: java.io.FileNotFoundException 使用合适的URL(包括协议!)。例如 另见: 试试: final In

如何从URL获取InputStream

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

我试过了

InputStream is = new FileInputStream("wwww.somewebsite.com/a.txt");
但我得到的是一个错误:

java.io.FileNotFoundException
使用合适的URL(包括协议!)。例如

另见:
试试:

final InputStream is = new URL("http://wwww.somewebsite.com/a.txt").openStream();
(a)
www.somewebsite.com/a.txt
不是“文件URL”。它根本不是一个URL。如果你把
http://
放在它的前面,它将是一个http URL,这显然是你在这里想要的

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


(c) 从任何URL获取输入流的方法是通过
URL.openStream(),
URL.getConnection().getInputStream(),
,这是等效的,但您可能有其他原因获取
URLConnection
并首先使用它。

您的原始代码使用FileInputStream,用于访问文件系统承载的文件

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


URL对象是解决此问题的通用方法。您可以使用URL访问本地文件,也可以访问网络承载的资源。URL类除了支持http://或https://之外,还支持file://协议,因此您可以继续使用。

下面是一个完整的示例,它读取给定网页的内容。 该网页是从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>  
ReadWebPage
servlet读取给定网页的内容,并以纯文本格式将其发送回客户端。阅读页面的任务委托给
webagereader

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);
    }
}
webagereader
验证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表单的主页。 这是我关于这个主题的文章。

纯Java:

 urlToInputStream(url,httpHeaders);
我成功地使用了这种方法。它处理重定向,并且可以作为
映射
传递不同数量的HTTP头。它还允许从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);
    }
}
私有输入流urlToInputStream(URL、映射参数){
HttpURLConnection con=null;
InputStream InputStream=null;
试一试{
con=(HttpURLConnection)url.openConnection();
con.设置连接超时(15000);
con.setReadTimeout(15000);
如果(args!=null){
对于(条目e:args.entrySet()){
con.setRequestProperty(e.getKey(),e.getValue());
}
}
con.connect();
int responseCode=con.getResponseCode();
/*默认情况下,连接将遵循重定向
*仅当HttpURLConnection的实现
*不执行重定向。具体行为取决于
*实际实现(例如sun.net)。
*!!!注意:此块允许连接到
*切换协议(例如HTTP到HTTPS),这不是
*默认行为。请参阅:https://stackoverflow.com/questions/1884230 
*更多信息!!!
*/
如果(响应代码<400&&responseCode>299){
字符串重定向URL=con.getHeaderField(“位置”);
试一试{
URL newUrl=新URL(重定向URL);
返回urlToInputStream(newUrl,args);
}捕获(格式错误){
URL newUrl=新URL(URL.getProtocol()+“:/”+URL.getHost()+重定向URL);
返回urlToInputStream(newUrl,args);
}
}
/*!!!!!*/
inputStream=con.getInputStream();
返回输入流;
}捕获(例外e){
抛出新的运行时异常(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);
    }
private InputStream getInputStreamFromUrl(URL URL、字符串用户、字符串密码)引发IOException{
String encoded=Base64.getEncoder().encodeToString((用户+”:“+passwd).getBytes(标准字符集.utf8));
Map httpHeaders=new Map();
httpHeaders.put(“接受”、“应用程序/json”);
httpHeaders.put(“用户代理”、“我的应用程序”);
httpHeaders.put(“授权”、“基本”+编码);
返回urlToInputStream(url,httpHeaders);
}

为什么要回滚删除
servlet
标记?这里不涉及
javax.servlet.
API。在带有
main()的普通Java类中执行此操作时,会遇到完全相同的问题
method。也许你应该熟悉URL是什么:你知道它是在每次读取InputStream时发出网络请求,还是一次读取整个文件,这样就不必在读取时发出网络请求?在Android的UI线程中调用此方法会引发异常。在后台线程中执行此操作。Use
HttpURLConnection
将已经遵循重定向,除非您告诉它不要这样做,但您没有这样做。我知道OP没有提到头,但我很欣赏这个简洁的(考虑到它是Java)示例。@EJP我添加了一些解释作为内联注释。我想,我主要针对HTTP 301将HTTP地址重定向到HTTPS地址的情况介绍了重定向块。当然,这超出了最初的问题,但这是一个默认实现无法处理的常见用例。请参阅:您的代码在没有重定向块的情况下同样可以正常工作,因为正如我前面所述,
HttpURLConnection
默认情况下已经遵循重定向。@使用
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);
    }