[英]Zip a great number of pdf file and download it: OutOfMemoryError: Java heap space
我想创建一个zip文件来下载它。 我有大量的pdf文件。
我需要将它们压缩为50MB的子zip,所以我创建了一个包含所有其他子zip的主zip。
但是当运行我的代码时,我得到:
Grave: Servlet.service() for servlet [appServlet] in context with path [/myProg] threw exception [Handler processing failed; nested exception is java.lang.OutOfMemoryError: Java heap space] with root cause
java.lang.OutOfMemoryError: Java heap space
这是我分割和压缩所有文件的代码:
public void zippatore(List<File> filesDaZippare, ZipOutputStream masterZos, String zipName, String pdfName) throws IOException{
float newSize = 0;
boolean first = true;
int count = 1;
File file;
ByteArrayOutputStream subBaos = new ByteArrayOutputStream();
ZipOutputStream subZos = new ZipOutputStream(subBaos);
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
while(filesDaZippare.size() > 0){
file = filesDaZippare.remove(0);
FileInputStream fis = new FileInputStream(file);
newSize += file.length();
String fileName = file.getName().substring(2);
if(newSize < MAX_SIZE || first){
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
subZos.closeEntry();
first = false;
}else{
subZos.flush();
subZos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
subZos = new ZipOutputStream(subBaos);
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
newSize = file.length();
first = true;
}
subZos.closeEntry();
}
subZos.closeEntry();
subZos.flush();
subZos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
}
我该如何解决?
编辑:我添加了代码以将我的子zip文件保存在tmp文件夹中。
File folder = new File(VariabiliGlobali.PATH_TMP);
byte[] buffer = new byte[1024];
for(File file : folder.listFiles()) {
FileInputStream fis = new FileInputStream(file);
masterZos.putNextEntry(new ZipEntry(file.getName()));
int length;
while ((length = fis.read(buffer)) > 0) {
masterZos.write(buffer, 0, length);
}
masterZos.closeEntry();
fis.close();
}
masterZos.flush();
masterZos.close();
获取所有zip文件并将其放入我的主zip文件中,但是将它们放入主zip文件中时会遇到相同的错误...
我是这样解决的:对于主zip文件,我使用了FileOutputStream
,而对所有其他子zip文件,我使用了ByteArrayOutputStream
,并且每隔50 MB刷新并关闭它一次。
因此,我不会对每个子zip文件都使用文件,因此使用流比使用文件要快。
这是代码:
FileOutputStream masterBos = new FileOutputStream(VariabiliGlobali.PATH_TMP+"Tmp.zip");
ZipOutputStream masterZos = new ZipOutputStream(masterBos);
public void zippatore(List<File> filesDaZippare, ZipOutputStream masterZos, String zipName, String pdfName) throws IOException{
float newSize = 0;
boolean first = true;
int count = 1;
File file;
ByteArrayOutputStream subBaos = new ByteArrayOutputStream();
ZipOutputStream subZos = new ZipOutputStream(subBaos);
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
while(filesDaZippare.size() > 0){
file = filesDaZippare.remove(0);
FileInputStream fis = new FileInputStream(file);
newSize += file.length();
String fileName = file.getName().substring(2);
if(newSize < MAX_SIZE || first){
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
subZos.closeEntry();
first = false;
}else{
subZos.flush();
subZos.close();
subBaos.flush();
subBaos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
subBaos = new ByteArrayOutputStream();
subZos = new ZipOutputStream(subBaos);
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
newSize = file.length();
first = true;
}
subZos.closeEntry();
}
subZos.closeEntry();
subZos.flush();
subZos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
}
从代码中可以看出,您正在将每个子zip压缩到一个由ByteArrayOutput流支持的输出流中,这将消耗内存。 将每个Sub文件写入磁盘上的临时位置,然后将单个zip推入主zip会减少您的内存需求,同时写入磁盘会产生开销,但是如果总体大小未知会是更好的方法。
只要磁盘有足够的空间来处理它,就可以将临时zip / subzip写入FileOutputstream而不是ByteArrayOutputStream来继续操作。
public void zippatore(List<File> filesDaZippare, ZipOutputStream masterZos, String zipName, String pdfName) throws IOException{
float newSize = 0;
boolean first = true;
int count = 1;
File file;
ByteArrayOutputStream subBaos = new ByteArrayOutputStream();
ZipOutputStream subZos = new ZipOutputStream(subBaos);
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
while(filesDaZippare.size() > 0){
file = filesDaZippare.remove(0);
FileInputStream fis = new FileInputStream(file);
newSize += file.length();
String fileName = file.getName().substring(2);
if(newSize < MAX_SIZE || first){
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
subZos.closeEntry();
first = false;
}else{
subZos.flush();
subZos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
masterZos.putNextEntry(new ZipEntry(zipName+" "+count++ +".zip"));
subBaos = new ByteArrayOutputStream();
subZos = new ZipOutputStream(subBaos);
subZos.putNextEntry(new ZipEntry(pdfName+" "+fileName+".pdf"));
IOUtils.copy(fis, subZos);
file.delete();
newSize = file.length();
first = true;
}
subZos.closeEntry();
}
subZos.closeEntry();
subZos.flush();
subZos.close();
masterZos.write(subBaos.toByteArray());
masterZos.closeEntry();
}
通过在服务器配置中指定VM参数来增加Java堆大小
例如:
-Xmx1024m
如果您在Eclipse中运行Tomcat,则可以在“服务器配置”的“打开启动”配置中指定VM参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.