代码之家  ›  专栏  ›  技术社区  ›  awj

更新ZipArchive中的文件

  •  1
  • awj  · 技术社区  · 6 年前

    我有一个ZipArchive对象,其中包含一个我正在修改的XML文件。然后我想返回修改过的ZipArchive。

    这是我的代码:

    var package = File.ReadAllBytes(/* location of existing .zip */);
    
    using (var packageStream = new MemoryStream(package, true))
    using (var zipPackage = new ZipArchive(packageStream, ZipArchiveMode.Update))
    {
        // obtain the specific entry    
        var myEntry = zipPackage.Entries.FirstOrDefault(entry => /* code elided */));
    
        XElement xContents;
        using (var reader = new StreamReader(myEntry.Open()))
        {
            // read the contents of the myEntry XML file
            // then modify the contents into xContents
        }
    
        using (var writer = new StreamWriter(myEntry.Open()))
        {
            writer.Write(xContents.ToString());
        }
    
        return packageStream.ToArray();
    }
    

    此代码在上引发“内存流不可扩展”异常 packageStream.ToArray() 打电话。

    有人能解释一下我做错了什么,更新ZipArchive中现有文件的正确方法是什么?

    1 回复  |  直到 6 年前
        1
  •  3
  •   elgonzo    6 年前

    显然, ZipArchive 希望扩展或调整zip存档流的大小。但是,您提供了 MemoryStream 用一个 固定的 流长度(由于使用了构造函数 MemoryStream(byte[], bool) ,它创建一个固定长度的内存流,该长度等于提供给构造函数的数组的长度)。

    自从 齐帕奇 希望扩展(或调整)流,提供可调整大小的 内存流 (使用其无参数构造函数)。然后将原始文件数据复制到此 内存流 然后继续压缩归档操作。

    别忘了重置 内存流 读/写位置返回 0 在将原始文件数据复制到其中之后,否则 齐帕奇 只会看到“ 流尾 “尝试从此流中读取zip存档数据时。

    using (var packageStream = new MemoryStream())
    {
        using (var fs = File.OpenRead(/* location of existing .zip */))
        {
            fs.CopyTo(packageStream);
        }
    
        packageStream.Position = 0;
    
    
        using (var zipPackage = new ZipArchive(packageStream, ZipArchiveMode.Update))
        {
            ... do your thing ...
        }
    
    
        return packageStream.ToArray();
    }
    

    这里的代码还包含一个更正。在问题的原始代码中, return packageStream.ToArray(); 已放置 在内部 这个 using 方块 齐帕奇 . 在执行此行时, 齐帕奇 实例可能尚未将所有数据写入 内存流 可能会将一些数据保留在一些内部缓冲区中和/或延迟写入某些zip数据结构。

    以确保 齐帕奇 已将所有必需的数据完全写入 内存流 ,这里足以移动 返回packageStream.toArray(); 在外面之后 齐帕奇 使用 块。在它的末尾 使用 齐帕奇 将被处理,这也将确保ZipArchive已经将所有到目前为止尚未写入的数据写入流中。因此,访问 内存流 齐帕奇 已释放将生成完全更新的zip存档的完整数据。


    旁注:只对小的ish-zip文件执行此操作。这个 内存流 显然将使用内部数据缓冲区(数组)将数据保存在 内存流 . 然而, packageStream.ToArray(); 将在 内存流 因此,在一段时间内,这个例程的内存需求将是zip存档大小的两倍多一点。