我正在尝试以zip格式存档文件列表,然后为用户即时下载...
下载1GB大小的zip时遇到内存不足的问题
请帮助我如何在不增加jvm堆大小的情况下解决此问题。我想定期冲洗水流。
我试图定期刷新,但是这对我来说不起作用。
请在下面找到我的代码:
try{
ServletOutputStream out = response.getOutputStream();
ZipOutputStream zip = new ZipOutputStream(out);
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition",
"attachment; filename=\"ResultFiles.zip\"");
//adding multiple files to zip
ZipUtility.addFileToZip("c:\\a", "print1.txt", zip);
ZipUtility.addFileToZip("c:\\a", "print2.txt", zip);
ZipUtility.addFileToZip("c:\\a", "print3.txt", zip);
ZipUtility.addFileToZip("c:\\a", "print4.txt", zip);
zip.flush();
zip.close();
out.close();
} catch (ZipException ex) {
System.out.println("zip exception");
} catch (Exception ex) {
System.out.println("exception");
ex.printStackTrace();
}
public class ZipUtility {
static public void addFileToZip(String path, String srcFile,
ZipOutputStream zip) throws Exception {
File file = new File(path + "\\" + srcFile);
boolean exists = file.exists();
if (exists) {
long fileSize = file.length();
int buffersize = (int) fileSize;
byte[] buf = new byte[buffersize];
int len;
FileInputStream fin = new FileInputStream(path + "\\" + srcFile);
zip.putNextEntry(new ZipEntry(srcFile));
int bytesread = 0, bytesBuffered = 0;
while ((bytesread = fin.read(buf)) > -1) {
zip.write(buf, 0, bytesread);
bytesBuffered += bytesread;
if (bytesBuffered > 1024 * 1024) { //flush after 1mb
bytesBuffered = 0;
zip.flush();
}
}
zip.closeEntry();
zip.flush();
fin.close();
}
}
}
}
最佳答案
您希望使用分块编码来发送一个很大的文件,否则servlet容器将在发送之前尝试找出要发送的数据大小,以便可以设置Content-Length标头。由于您正在压缩文件,因此您不知道要发送的数据大小。块编码允许您以较小的块发送响应。不要设置流的内容长度。您可以尝试使用curl或其他方式查看从服务器获取的响应中的HTTP标头。如果没有分块,那么您将需要弄清楚。您将要研究如何强制Servlet容器发送分块编码。您可能必须将其添加到响应标头中,以使Servlet容器将其发送成块。
response.setHeader("Transfer-Encoding", "chunked");
另一个选择是使用File.createTemp()将文件压缩为一个临时文件,然后发送该文件的内容。如果先压缩为临时文件,则可以知道该文件有多大,并设置servlet的内容长度。
关于java - 如何在Java中定期刷新ZipOutputStream,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7108035/