[英]Read an InputStream from a URL and Write to HttpServletResponse without creating a temp file
我尝试从URL读取一个InputStream并直接写入HttpServletResponse而不在HttpServlet中创建临时文件,但未能获得该文件的实际Content-Length。 我被告知,如果不读取数据,我无法确定流中的数据量。 有人能帮我吗? 我真的很感激。
由于您正在读取URL,因此您应该从该URL的Content-length
标头中获取Content-length
。
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.connect();
if ( connection.getResponseCode() == 200 ) {
int contentLength = connection.getContentLength();
response.setContentLength( contentLength );
请注意,你不应该使用inputStream.available()
available()
方法只是告诉你可以在不阻塞的情况下读取多少字节(即等待下一个块从网络到达)。 它没有告诉你流的大小! 但是在HttpURLConnection
,您可以使用getContentLength()
方法获取content-length头的值。
一旦这样做,您就可以启动读写循环来复制所有数据,例如
InputStream source = connection.getInputStream();
OutputStream target = response.getOutputStream();
int FILE_CHUNK_SIZE = 1024 * 4;
byte[] chunk = new byte[FILE_CHUNK_SIZE];
int n =0;
while ( (n = source.read(chunk)) != -1 ) {
target.write(chunk, 0, n);
}
请记住在所有这些中使用try-catch,因为在这样的事务中可能会抛出多种异常。 当您发现异常时,请记住在响应中设置响应代码,该代码不是 200。
在数据耗尽之前,没有理由无法从请求对象中读取输入流 - 将其缓冲到内存中。 事实上,根据我的经验,这总是如何完成的; 我可以指望一只手的手指我看到输入流写入文件而不是缓冲到内存中的次数。 如果你得到一个内容长度标题,你可以用它作为起点,但我不会依赖它。 你需要防止太多的输入,因为你不知道输入流的远端是什么,所以他们服务器你正在联系你可能会发送很多材料,你用尽RAM来处理它。
只需继续调用read()直到得到-1。 其他读取方法也可用于此,但您将添加更多逻辑来检测文件结束。
我使用这段代码,没有进行内容长度管理(IOUtils在commons-io中并且不创建临时文件)但是适用于小文件和大文件:
public static void downloadFile(HttpServletResponse response, InputStream inputStream, String fileName,
String contentType) throws IOException {
response.reset();
response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"",
fileName));
if (contentType != null) {
response.setHeader("Content-Type", contentType);
}
OutputStream output = response.getOutputStream();
IOUtils.copy(inputStream, output);
output.flush();
output.close();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.