我正在使用 java 读取 ZIP 文件,如下所示:
Enumeration<? extends ZipEntry> zes=zip.entries();
while(zes.hasMoreElements()) {
ZipEntry ze=zes.nextElement();
// do stuff..
}
Run Code Online (Sandbox Code Playgroud)
我收到内存不足错误,zip 文件大小约为 160MB。堆栈跟踪如下:
Exception in thread "Timer-0" java.lang.OutOfMemoryError: Java heap space
at java.util.zip.InflaterInputStream.<init>(InflaterInputStream.java:88)
at java.util.zip.ZipFile$1.<init>(ZipFile.java:229)
at java.util.zip.ZipFile.getInputStream(ZipFile.java:229)
at java.util.zip.ZipFile.getInputStream(ZipFile.java:197)
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.zipFilePass2(DatToInsertDBBatch.java:250)
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.processCompany(DatToInsertDBBatch.java:206)
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.run(DatToInsertDBBatch.java:114)
at java.util.TimerThread.mainLoop(Timer.java:534)
at java.util.TimerThread.run(Timer.java:484)
Run Code Online (Sandbox Code Playgroud)
如何在不增加堆大小的情况下枚举大 zip 文件的内容?另外,当我不枚举内容而只访问单个文件时,如下所示:
ZipFile zip=new ZipFile(zipFile);
ZipEntry ze=zip.getEntry("docxml.xml");
Run Code Online (Sandbox Code Playgroud)
然后我就不会出现内存不足的错误。为什么会出现这种情况?Zip 文件如何处理 zip 条目?另一种选择是使用 ZIPInputStream。内存占用会小吗?我最终需要在 Amazon 云上的微型 EC2 实例(613 MB RAM)上运行此代码
编辑:提供有关我收到 zip 条目后如何处理它们的更多信息
Enumeration<? extends ZipEntry> zes=zip.entries();
while(zes.hasMoreElements()) {
ZipEntry ze=zes.nextElement();
S3Object s3Object=new S3Object(bkp.getCompanyFolder()+map.get(ze.getName()).getRelativeLoc());
s3Object.setDataInputStream(zip.getInputStream(ze));
s3Object.setStorageClass(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY);
s3Object.addMetadata("x-amz-server-side-encryption", "AES256");
s3Object.setContentType(Mimetypes.getInstance().getMimetype(s3Object.getKey()));
s3Object.setContentDisposition("attachment; filename="+FilenameUtils.getName(s3Object.getKey()));
s3objs.add(s3Object);
}
Run Code Online (Sandbox Code Playgroud)
我从 zipentry 获取 zipinputstream 并将其存储在 S3object 中。我将所有 S3Object 收集到一个列表中,然后最终将它们上传到 Amazon S3。对于那些不了解 Amazon S3 的人来说,它是一种文件存储服务。您通过 HTTP 上传文件。
我在想,也许是因为我收集了所有单独的输入流,所以才会发生这种情况?如果我把它批量化会有帮助吗?比如一次 100 个输入流?或者,如果我先解压缩它,然后使用解压缩的文件上传而不是存储流会更好吗?
由于处理 ZIP 文件而出现内存不足异常的可能性很小。Java 类ZipFile不ZipEntry包含任何可能填满 613 MB 内存的内容。
将 ZIP 存档的解压缩文件保留在内存中可能会耗尽您的内存,或者更糟糕的是,将它们保留为 XML DOM,这非常占用内存。
切换到另一个 ZIP 库几乎没有帮助。相反,您应该考虑更改代码,以便它像流一样处理 ZIP 存档和包含的文件,并且一次仅将每个文件的有限部分保留在内存中。
顺便说一句:如果您能提供有关大型ZIP 文件(它们包含许多小文件还是几个大文件?)以及如何处理每个 ZIP 条目的更多信息,我会很高兴。
更新:
感谢您的附加信息。看起来您将 ZIP 文件的内容保留在内存中(尽管这在某种程度上取决于类的实现S3Object,我不知道)。
最好按照您自己的建议实施某种批处理。例如,您可以将每个 ZIP 条目的解压缩大小相加,并在每次总大小超过 100 MB 时上传文件。