繁体   English   中英

在java中读取一个巨大的Zip文件 - Out of Memory Error

[英]Reading a huge Zip file in java - Out of Memory Error

我正在使用java读取ZIP文件,如下所示:

Enumeration<? extends ZipEntry> zes=zip.entries();
    while(zes.hasMoreElements()) {
        ZipEntry ze=zes.nextElement();
        // do stuff..
    }

我收到内存不足错误,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)

如何在不增加堆大小的情况下枚举大型zip文件的内容? 此外,当我不枚举内容,只是访问这样的单个文件:

ZipFile zip=new ZipFile(zipFile);
ZipEntry ze=zip.getEntry("docxml.xml");

然后我没有得到内存不足的错误。 为什么会这样? Zip文件如何处理zip条目? 另一种选择是使用ZIPInputStream。 这会占用很少的内存吗? 我需要最终在亚马逊云上的微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);
    }

我从zipentry获得zipinputstream并将其存储在S3object中。 我收集列表中的所有S3Objects,然后最终将它们上传到Amazon S3。 对于那些不了解Amazon S3的人来说,它是一个文件存储服务。 您通过HTTP上传文件。

我想也许是因为我收集了所有这些正在发生的输入流? 如果我把它批量化它会有帮助吗? 像一次100输入流? 或者,如果我先解压缩然后使用解压缩文件上传而不是存储流,会不会更好?

由于处理ZIP文件而导致内存不足异常非常不可思议。 Java类ZipFileZipEntry不包含任何可能填满613 MB内存的内容。

可能会耗尽内存的是将ZIP存档的解压缩文件保留在内存中,或者 - 更糟糕的是 - 将它们保存为XML DOM,这是一个非常耗费内存的问题。

切换到另一个ZIP库几乎没有帮助。 相反,您应该考虑更改代码,以便它处理ZIP存档和包含的文件(如流),并且每次只将每个文件的有限部分保留在内存中。

顺便说一句:如果你能提供关于巨大的 ZIP文件的更多信息(它们包含许多小文件或几个大文件吗?)以及你对每个ZIP条目的处理方式,我会很高兴。

更新:

感谢您的附加信息。 看起来你将ZIP文件的内容保存在内存中(尽管它在某种程度上取决于S3Object类的实现,我不知道)。

你自己提出的建议最好是实施某种批处理。 例如,您可以添加每个ZIP条目的解压缩大小,并在每次总大小超过100 MB时上载文件。

正如我所见,你现在正在使用ZipFile类。 可能使用ZipInputStream将是一个更好的选择,因为它有'closeEntry()'方法(我希望)解除分配条目使用的内存资源。 但我之前没有使用它,这只是猜测。

JVM的默认大小为64MB。 您需要在命令行上指定更大的大小。 使用-Xmx开关。 例如-Xmx256m

实际上,java.util.zip.ZipFile有一个size()方法,但不提供按索引访问条目的方法。 也许您需要使用不同的ZIP库。 我记得,我使用了相当大的档案的TrueZIP

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM