在ZipFile中添加大量文件时出现OutOfMemoryException

时间:2017-11-13 15:13:44

标签: c# .net zip zipfile dotnetzip

当我在 ZipFile 中添加大量数量的文件时,我遇到了 OutofMemoryException 的问题。示例代码如下:

ZipFile file = new ZipFile("E:\\test1.zip");
file.UseZip64WhenSaving = Zip64Option.AsNecessary;
file.ParallelDeflateThreshold = -1;
for (Int64 i = 0; i < 1000000; i++)
{
   file.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
   byte[] data = Encoding.ASCII.GetBytes("rama");
   ZipEntry entry = file.AddEntry(@"myFolder1/test1/myhtml111.html" + i.ToString(), data);
}
file.Save();

我已经下载了 Ionic.zip 库的源代码,我看到每个Add *()函数都有AddEntry(),AddFile()等,他们将项添加到Dictionary中称为 _entry 即可。

当我们在 ZipFile 上调用保存() Dispose()方法时,此词典不会清除对象

我觉得这是O​​utOfMemoryException的根本原因。

我如何克服这个问题?有没有其他方法可以实现相同的结果而不会遇到OutOfMemoryException?我错过了什么吗? 我也愿意使用其他开源库。

1 个答案:

答案 0 :(得分:0)

保存档案内部结构的字典应该不成问题。 假设您输入的路径是&#39;是一个大约 50 字节的字符串 - 即使是1000000个条目也应该大约 50 Mb (很多 - 但是没有接近2 Gb的限制) - 而我没有&#39检查ZipEntry的大小 - 我也怀疑它是否足够大(每个需要大约2kb)

我也认为你对这个Entry词典的期望被清除是错误的。由于这是zip文件内容的信息结构 - 您需要它来保存所有条目。

从这一点开始,我将假设发布的代码:

byte[] data = Encoding.ASCII.GetBytes("rama");

是以字节为单位的实际文件数据的占位符(因为对于1M x 4字节 - 应该低于4Mb)

这里最有可能的问题是声明的byte []数据保留在内存中,直到整个ZipFile被释放。 保持此数组直到保存数据是有意义的。 解决此问题的最简单方法是使用重新打开和关闭ZipFile来为每个要添加的文件打包。

        var zipFileName = "E:\\test1.zip";
        for (int i = 0; i < 1000000; ++i)
        {
            using (ZipFile zf = new ZipFile(zipFileName))
            {

                byte[] data = File.ReadAllBytes(file2Zip);

                ZipEntry entry = zf.AddEntry(@"myFolder1/test1/myhtml111.html" + i.ToString(), data);

                zf.Save();
            }

        }

如果要保存大量小文件,这种方法可能看起来很浪费,因为直接使用byte []实现缓冲机制非常简单。

虽然确实可以通过编译为64位来解决这个问题,但除非你真的只是略微超过2Gb的限制,否则这将创建一个非常耗费内存的应用程序。