private void downloadAllRelease(HttpServletRequest request,
HttpServletResponse response) {
LoginToken tok=getToken(request, response);
int size = 0;
try {
ArrayList<Release> releases = manager.getReleases(tok.getUsername);
ZipOutputStream out = new ZipOutputStream(response.getOutputStream());
for (int i=0; i<releases.size(); i++) {
size += releases.get(i).getFile().length;
out.putNextEntry(new ZipEntry(releases.get(i).getFilename()));
out.write(releases.get(i).getFile());
out.closeEntry();
}
response.setContentLength(size);
response.setContentType("application/force-download");
response.setHeader("Content-Disposition","attachment;filename=release.zip");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
response.setContentLength()
降低了下载速度。
如果我不使用它或在out.close()
之后使用它,一切仍然可以正常工作,但下载速度会快得多
有人可以解释我为什么以及是否有必要使用response.setContentLength()
?
答案 0 :(得分:22)
也许是因为你指定的大小比实际发送到响应的大,并且webbrowser基本上会混淆并等待更多数据?你知道,ZIP压缩文件并减少最终的大小。
如果您事先无法有效地计算,请不要指定响应的内容长度。无论如何,servlet容器将automatically以chunked encoding发送它。没错,这会产生更多的开销,并使Web浏览器的下载进度不明,但这并不需要先在服务器内存中缓冲整个响应,以便获得正确的最终响应内容长度。
如果确实想要计算最终回复内容的长度,则需要将其全部写入ByteArrayOutputStream
,然后通过{byte[]
获取toByteArray()
{1}}方法。实际响应内容长度是byte[]
的长度。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
// ...
response.setContentLength(baos.size());
response.getOutputStream().write(bytes);
这只是占用更多内存,因为所有内容都将首先存储在服务器的内存中。如果多个用户同时执行此操作并且zip输出相对较大,那么您的服务器可能会迟早会耗尽内存。作为另一种选择,您可以使用FileOutputStream
将其写入由File#createTempFile()
创建的临时文件,以便您可以File#length()
获取其大小并使用FileInputStream
对其进行流式处理通常的方式直接进入响应的OutputStream
。这只是较慢,因为你基本上将字节转移了两次。