【问题标题】:C# OutOfMemoryException creating ZipOutputStream using SharpZipLibC# OutOfMemoryException 使用 SharpZipLib 创建 ZipOutputStream
【发布时间】:2023-03-29 09:42:01
【问题描述】:

我在以下代码中不断收到非常烦人的 OutOfMemory 异常。

我正在压缩很多小文件(PDF,每个大约 1.5mb)。

起初我在压缩 25 个文件后遇到了异常,这看起来不像是一个庞大的存档。

设置 ZipEntry 的大小在某种程度上有所帮助,因为现在我设法压缩了多达 110 个文件(我正在 Visual Studio 下调试)

这是我的代码,可能有问题。

任何帮助将不胜感激。

谢谢

    public static MemoryStream Zip(Dictionary<string, byte[]> files)
    {
        var outputMemStream = new MemoryStream();

        var zipStream = new ZipOutputStream(outputMemStream);

        zipStream.SetLevel(9);
        foreach (var file in files)
        {
            zipStream.PutNextEntry(new ZipEntry(file.Key.FmtValidFileName())
                {
                    Size = file.Value.Length
                });
            zipStream.Write(file.Value, 0, file.Value.Length);
            zipStream.Flush();
        }           
        zipStream.Finish();
        outputMemStream.Position = 0;
        return outputMemStream;
    }

【问题讨论】:

  • 实现IDisposible 的每个类都需要放入using 块中。如果您有支持它的 Visual Studio 版本,则可以打开静态代码分析,以便在忘记正确执行时收到警告。
  • 恐怕没用。 OutOfMemoryException 发生在文件的循环内。我不能将 outputMemStream 放在 using 中,因为我将它用作返回。我尝试使用缓冲区而不是完全写入文件,但这也无济于事,问题不在于我要压缩的每个文件的大小,而是所有文件的总大小。
  • 您应该创建一个小型、独立的示例。据我们所知,FmtValidFileName 可以由throw new OutOfMemoryException(); 组成。准备一个示例,人们可以使用最佳实践复制和编译自己,它会更容易为您提供帮助。
  • FmtValidFileName 是字符串的扩展方法,用于从正在压缩的文件名中删除任何模糊字符,因此这不是问题。此外,我不能提供比我给出的代码提取更多的东西,它是我得到的最小的,我正在针对由 160 条记录组成的 Dictionary 文件运行它,每个 byte[] 大约为 1434167 字节大约是 1.3Mb,它会在压缩大约 100 个文件后抛出 OutOfMemory。

标签: c# zip out-of-memory zipoutputstream


【解决方案1】:

与往常一样,简洁而完整的代码示例将大大有助于您获得良好的答案。

也就是说,您可能需要考虑在 .NET 中使用(相对较新的)System.IO.Compression.ZipArchive 类。它可能比第三方库更少错误和/或更可靠(尽管我承认 SharpZipLib 相当受尊重:))。

更重要的是,您可以使用ZipArchiveMode.Create 值实例化一个新的ZipArchive 对象,这将导致压缩数据直接写入流而不是缓存在内存中。在这种模式下,无论您尝试创建多少数据或归档项目,内存不足错误都应该不存在。

编辑:还有一件事:为了完全避免内存不足的问题,请确保无论您使用什么 .zip 实现,都直接写入磁盘。写入内存中的临时MemoryStream 当然会对您的进程施加限制,否则不会发生。

【讨论】:

  • 谢谢,我会试试的,但我得问一下我的代码示例有什么问题?恕我直言,它既简洁又完整。
  • 一个完整的代码示例是我或其他任何人都可以将其复制到一个空项目中,然后在不添加 anything 的情况下编译和运行。在某些情况下这样做很棘手,例如这个例子,因为示例必须包含或生成重现问题所需的测试数据。但是,虽然您的代码示例非常简洁,但它并不完整。
  • 在 StackOverflow 中很少看到任何这些,但很公平,我完全可以理解愿意提供帮助的人不会花费任何时间来生成必要的输入来重现我的代码问题。
  • 我同意它们很少见。关于 SO 的问题有 很多。我同意你在这里发布的那个是更好的之一。但归根结底,即使没有成功的保证,也很少有人会花很多时间来充实现有的示例,以便它运行并重现问题。所以你只剩下纯粹的推测性答案,这些答案永远不如中肯、全面的答案。 :)
  • 使用 ZipArchive 并没有改变,但我认为我的问题是从 Visual Studio 运行的 IIS 服务器是 32 位的,我达到了自然内存限制。
【解决方案2】:

我放弃了尝试使用 MemoryStream 的尝试,即使在具有 16gb 内存的 64 位系统上我应该在这方面是安全的。

我找到的相关话题是:OutOfMemoryException while populating MemoryStream: 256MB allocation on 16GB system

并使用临时文件而不是内存来写入/读取数据。

【讨论】:

    猜你喜欢
    • 2011-03-23
    • 2019-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    相关资源
    最近更新 更多