使用 Ionic 创建大型多部分 zip 失败并出现 OutOfMemoryException

Posted

技术标签:

【中文标题】使用 Ionic 创建大型多部分 zip 失败并出现 OutOfMemoryException【英文标题】:Creating large multi-part zip with Ionic fails with OutOfMemoryException 【发布时间】:2016-08-19 06:59:31 【问题描述】:

我尝试使用 IonicZip 创建一个包含总大小为 17 GB 的文件的多部分 zip 文件。

每个 zip 部分设置为不大于 500 MB 左右。

zip.MaxOutputSegmentSize = 500000000;

进入 zip 的文件大小不一,但从不超过 350MB,通常小得多,只有几 KB 或 MB。

我创建 zip 文件的机器有 4GB 内存。

当我在我的程序中开始创建 zip 时,由于使用了 RAM,我有时会收到一个 OutOfMemoryException

(当所有文件的总大小约为 2 GB 而不是 17 GB 时,同样可以正常工作)。

代码:

ZipFile zip = new ZipFile(zipFileName, Encoding.UTF8);
zip.CompressionLevel = CompressionLevel.BestCompression;

zip.ParallelDeflateThreshold = -1; // https://***.com/questions/11981143/compression-fails-when-using-ionic-zip
zip.MaxOutputSegmentSize = 500000000; // around 500MB

[...]

while (...)

  zip.AddEntry(adjustedFilePath, File.ReadAllBytes(filepath));


zip.Save();

我想知道 IonicZip 如何结合多部分创建处理 zip.save。不必将所有多部分保存在内存中,而只保存当前部分,不是吗?

由于我将 zip.MaxOutputSegmentSize 设置为仅 500MB 左右,并且进入 zip 的单个文件的最大大小从不超过 350MB,我不明白为什么它会占用这么多内存。

另一方面,当 OutOfMemoryException 发生时,甚至还没有多部分的任何单个部分写入磁盘。通常,当 zip 创建成功的文件数量较少时,多个部分在文件系统上具有不同的创建时间戳,大约每次间隔 5 秒。所以我真的不确定 IonicZip 在内部到底在做什么,直到它吐出第一个 zip 部分。

抱歉,我是 C# 和 .NET 的新手。 IonicZip 是最好的库吗?我可以改用 System.IO.Compression 或 System.IO.Packaging 包(我没有看到它们支持多部分 zip)或商业 Xceed?

我已经检查过但没有帮助的帖子:

Compression fails when using ionic zip Ionic zip throws out of memory exception OutOfMemoryException when creating large ZIP file using System.IO.Packaging(与 IonicZip 无关)

【问题讨论】:

【参考方案1】:

我建议使用内置的 .net System.IO.Compression 命名空间类来压缩/解压缩文件;它们是基于流的,而您在此处的示例不使用流-因此必须使用 RAM 来存储压缩数据。使用 .net 原生库,您可以将压缩数据分块写入输出流。

【讨论】:

谢谢。这个包是否支持多部分拉链,因为我在 Google 或 msdn.microsoft.com/de-de/library/… 中找不到任何关于它的信息 Zip 支持,但其他 (GZip) 不支持。 您能否指出一些可以设置拆分大小的在线 API 文档?我仍然看不到我可以通过System.IO.Compression 包做到这一点。现在我正在测试 Xceed (xceed.com/xceed-zip-for-net) 库作为替代方案,我可以简单地说 zip.splitSize= 500000000。到目前为止,我看不到内存使用量有任何增加,但它仍在压缩我的 17GB。 抱歉 - 我不知道 SplitSize 是什么或它的用途。 创建一个多部分的 zip 文件。由于我需要压缩 17GB 的文件,我不想有一个大的 zip 文件,而是分成多个,所以最后我会有 myfiles.zip、myfiles.z01、myfiles.z01 等每个不大于 500MB。特别是因为 zip 格式每个文件的大小限制为 4GB。 “SplitSize”只是 Xceed 用来定义此类零件的最大尺寸的参数名称。在 IonicZip 中,它被称为“MaxOutputSegmentSize”。【参考方案2】:

我想出的解决方案在努力方面似乎是最好的(我不想重新发明***并为标准 zip/压缩包编写多部分逻辑,这似乎是一个标准的事情这应该是任何压缩包的一部分)是使用Xceed,并且几乎使用与 IonicZip 相同的代码逻辑。

似乎 IonicZip 在内存方面并没有真正以有效的方式处理它。 Xceed 运行良好,没有显着增加内存使用量。

        using Xceed.Zip;
        using Xceed.FileSystem;

        [...]

        ZipArchive zip = new ZipArchive(new DiskFile(zipFileName));
        zip.SplitNameFormat = SplitNameFormat.PkZip;
        zip.SplitSize = 500000;
        zip.DefaultCompressionLevel = Xceed.Compression.CompressionLevel.Highest;
        zip.TempFolder = new DiskFolder(@"C:\temp");
        new DiskFolder(localSourceFolder).CopyFilesTo(zip, true, true);

【讨论】:

以上是关于使用 Ionic 创建大型多部分 zip 失败并出现 OutOfMemoryException的主要内容,如果未能解决你的问题,请参考以下文章

Ionic.Zip 提取文件并忽略密码

如何创建具有低 memory_limit 的大型 zip 文件?

失败 - 在 chrome 中获取 Zip 文件时出现网络错误

C#调用Ionic.Zip类压缩文件夹

如何在 C# 中使用 Ionic-zip 下载大文件时修复 zip 文件损坏错误

Gradle distributionUrl 使用“ionic cordova run android”更改为旧版本,构建失败