我在我的应用程序中使用DotNetZip
1.9.6,它使用类似于例如文件结构的文件结构。 * .docx:包含XML文件的Zip文件
现在,应用程序的每个模块都可以将这些XML文件存储到我的自定义文件管理中,然后保存"保存"它们被序列化为流,然后通过DotNetZip保存到Zip文件中
要更新条目,请使用ZipFile.UpdateEntry(path, stream)
。
这工作正常,我第一次通过调用ZipFile.Save()
保存我的文件一切正常。
但是,如果我在同一个实例上第二次(先是UpdateEntry
次调用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包。
答案 0 :(得分:2)
这似乎是图书馆中的一个错误,即删除条目。如果只是删除一个条目然后再次保存,它会正确删除该文件。
但是,如果删除一个条目,然后添加另一个具有相同名称的条目 - 如果该条目已存在,则记录UpdateEntry
要执行的操作 - 似乎使用旧条目。
您第二次以空文件结束的原因是原来的MemoryStream
正在被再次阅读 - 但到目前为止,它位于数据的末尾,所以没有数据可供阅读。如果将位置重置为流的开头(content1.Position = 0;
),它将重写原始数据。如果您修改 content1
中的数据,则最终会得到无效的压缩数据。
我能立即想到的唯一解决方法是将您自己的地图从文件名保留到MemoryStream
,并在您想要更新时替换每个MemoryStream
的内容...或者只是加载根据您现有的解决方法,每次都提交文件。
这绝对值得在此处提出一个错误,因为它应该尽我所能。
答案 1 :(得分:0)
正如已经怀疑这是DotNetZip
版本1.9.6
之前的错误
我想我能够通过THIS更改解决这个问题,该更改刚刚在NuGet上作为版本1.9.7
发布。至少对我来说问题不再发生了。
根据我的发现,发生了一些背景:
当您调用Save
时,库会设置一个内部标志,该内部标志会记住ZIP文件只是保存,并且在第二次Save
调用而不是“重新压缩”ZIP文件中的所有条目时,它会从刚刚复制它们保存的文件
这适用于添加/删除条目,但在其中一个条目更改时中断,然后它“混合”旧条目和新条目并生成不一致的ZIP文件。
如果条目被更改,我的修复程序基本上禁用“从旧文件复制”逻辑。