【问题标题】:Corrupt ZIP file if calling Save twice如果调用保存两次损坏 ZIP 文件
【发布时间】:2015-09-23 07:54:53
【问题描述】:

我在我的应用程序中使用DotNetZip 1.9.6,它使用类似于例如*.docx:包含 XML 文件的 Zip 文件。
现在,应用程序的每个模块都可以将此类 XML 文件存储到我的自定义文件管理中,并在“保存”时将它们序列化为流,然后通过 DotNetZip 将其保存到 Zip 文件中。
要更新我使用ZipFile.UpdateEntry(path, stream) 的条目。 这很好用,我第一次通过调用ZipFile.Save() 保存文件时一切正常。

但是,如果我在同一实例上第二次执行此操作(首先是一些 UpdateEntrycalls,然后是 Save),则 Zip 文件已损坏:文件结构和元数据(例如每个文件的未压缩大小)仍然存在在那里,但所有文件的压缩大小都是 0 字节。

如果我在保存一切正常后从刚刚保存的文件创建一个新实例,但是否可以避免这种情况并“重用”同一个实例?

以下示例(另见https://dotnetfiddle.net/mHxEIy)可用于重现该问题:

using System.IO;
using System.Text;

public class Program
{
    public static void Main()
    {
        var zipFile = new Ionic.Zip.ZipFile();

        var content1 = new MemoryStream(Encoding.Default.GetBytes("Content 1"));
        zipFile.UpdateEntry("test.txt", content1);

        zipFile.Save("test.zip"); // here the Zip file is correct
        //zipFile = new Ionic.Zip.ZipFile("test.zip"); // uncomment and it works too

        var content2 = new MemoryStream(Encoding.Default.GetBytes("Content 2"));
        zipFile.UpdateEntry("test.txt", content2);

        zipFile.Save();  // after that it is corrupt
    }
}

要运行它,您需要添加“DotNetZip 1.9.6”NuGet 包。

第一次保存后,你会得到:

第二次保存后:

【问题讨论】:

  • 好多了,谢谢 - 是的,让我们删除 cmets...

标签: c# stream zip dotnetzip


【解决方案1】:

这看起来像是库中的一个错误,与删除条目有关。如果您只是删除一个条目然后再次保存,它会正确删除该文件。

但是,如果您删除一个条目,然后添加另一个具有相同名称的条目 - 这是 UpdateEntry 在条目已存在的情况下所记录的操作 - 似乎会使用旧条目。

您第二次得到一个空文件的原因是原来的MemoryStream 正在被再次读取 - 但现在,它位于数据的末尾,因此没有要读取的数据。如果将位置重置为流的开头 (content1.Position = 0;),它将重写原始数据。如果您修改content1 中的数据,您最终会得到无效的压缩数据。

我能立即想到的唯一解决方法是将您自己的地图从文件名保留为MemoryStream,并在您想要更新它时替换每个MemoryStream 的内容......或者每次只加载文件,根据您现有的解决方法。

这绝对值得提交一个错误,因为据我所知,它应该工作。

【讨论】:

  • 感谢您的回答和您花时间研究这个问题 - 我将在 GitHub 中为 DotNetZip 提交一个错误,如果出现问题,请在此处报告...
  • 正如刚刚发布的新答案:我想我能够修复这个错误并且刚刚发布了一个新版本的DotNetZip。再次感谢您的帮助 - 它帮助我找到了正确的地方。
【解决方案2】:

正如已经怀疑的那样,这是DotNetZip 直到版本1.9.6 中的一个错误。
我想我可以通过 THIS 更改解决此问题,该更改刚刚在 NuGet 上作为版本 1.9.7 发布。至少对我来说,这个问题不再发生了。

据我所知发生的一些背景:
当您调用 Save 时,库会设置一个内部标志,它会记住 ZIP 文件刚刚保存,并且在第二次 Save 调用而不是“重新压缩”ZIP 文件中的所有条目时,它会从刚刚保存的文件中复制它们。 这适用于添加/删除条目,但是当其中一个条目发生更改时会中断,因为它会“混合”旧条目和新条目并生成不一致的 ZIP 文件。
如果条目被更改,我的修复基本上会禁用“从旧文件复制”逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-14
    • 1970-01-01
    • 2023-03-24
    • 2014-11-16
    • 2018-03-20
    相关资源
    最近更新 更多