来自 URL 的 InputStream
Posted
技术标签:
【中文标题】来自 URL 的 InputStream【英文标题】:InputStream from a URL 【发布时间】: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
【问题讨论】:
你为什么回滚删除servlets
标签?这里不涉及javax.servlet.*
API。在使用 main()
方法的普通 Java 类中这样做时,您会遇到完全相同的问题。
或许您应该熟悉一下什么是 URL:docs.oracle.com/javase/tutorial/networking/urls/definition.html
【参考方案1】:
使用 java.net.URL#openStream()
和正确的 URL(包括协议!)。例如
InputStream input = new URL("http://www.somewebsite.com/a.txt").openStream();
// ...
另见:
Using java.net.URLConnection to fire and handle HTTP requests【讨论】:
您是否知道这是否会在每次读取 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://***.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 地址的情况下的重定向块。当然,这超出了最初的问题,而是默认实现不处理的常见用例。见:***.com/questions/1884230/…
您的代码在没有重定向块的情况下同样有效,因为HttpURLConnection
默认情况下已经遵循重定向,正如我已经说过的那样。
@user207421 这部分正确。重定向块用于协议切换,例如 http->https,默认情况下不支持。我试图在代码注释中表达这一点。见***.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 关于这个话题。
【讨论】:
以上是关于来自 URL 的 InputStream的主要内容,如果未能解决你的问题,请参考以下文章
无法在android的videoview中播放来自url的视频如何在videoview中播放来自URL的视频?
来自 C# 中的基本 URL + 相对 URL 的绝对 URL