来自 URL 的 InputStream

如何从 URL 获得 InputStream?

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

我试过了

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

但我得到的是一个错误:

java.io.FileNotFoundException
195497 次浏览

使用带有正确 URL (包括协议!)的 java.net.URL#openStream()

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

参见:

试试:

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

(a) wwww.somewebsite.com/a.txt不是「档案网址」。这根本不是网址。如果您将 http://放在它的前面,那么它将是一个 HTTP URL,这显然就是您在这里想要的。

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

(c)从 任何 URL 获得输入流的方法是通过 URL.openStream(),URL.getConnection().getInputStream(),,这是等价的,但你可能有其他原因得到的 URLConnection和发挥它第一。

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

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

URL 对象是解决这个问题的通用方法。您可以使用 URL 访问本地文件,也可以使用网络托管资源。URL 类除了 http://或 https://之外还支持文件://protocol,因此可以使用它。

下面是一个完整的例子,它读取给定网页的内容。 网页是从 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>

我们使用 ApacheCommons 库来验证 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 表单的主页。 这是从我的 教程关于这个主题。

纯爪哇:

 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);
}