更新 ZipArchive 中的文件
Update a file in a ZipArchive
我有一个 ZipArchive 对象,其中包含一个我正在修改的 XML 文件。然后我想 return 修改后的 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()
调用中引发 "Memory stream is not expandable" 异常。
任何人都可以解释我做错了什么,更新 ZipArchive 中现有文件的正确方法是什么?
显然,ZipArchive
想要扩展或调整 ZIP 存档流的大小。但是,您提供了 MemoryStream
和 固定 流长度(由于使用了构造函数 MemoryStream(byte[], bool)
,它创建了一个固定长度的内存流,该长度等于到提供给构造函数的数组的长度)。
由于 ZipArchive
想要扩展(或调整大小)流,提供可调整大小的 MemoryStream
(使用其无参数构造函数)。然后将原始文件数据复制到此 MemoryStream 并继续进行 ZIP 存档操作。
并且不要忘记将MemoryStreamread/write位置重置回0
后将原始文件数据复制到其中,否则ZipArchive 尝试从此流中读取 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();
已被放置在 内 ZipArchive 的 using
块中。在执行这一行时,ZipArchive 实例可能还没有将所有数据写入 MemoryStream,也许某些数据仍在一些内部缓冲区 and/or 可能推迟了一些 ZIP 数据结构的写入。
为了确保 ZipArchive 实际上已经将所有必要的数据完全写入 MemoryStream,移动 return packageStream.ToArray();
在 ZipArchive using
块之后。在其 using
块的末尾,ZipArchive 将被释放,这也将确保 ZipArchive 已将所有尚未写入的数据写入流。因此,在 ZipArchive 被清除后访问 MemoryStream 将产生完全更新的 ZIP 存档的完整数据。
旁注:仅对较小的 ZIP 文件执行此操作。 MemoryStream 显然会使用内部数据缓冲区(数组)来保存 MemoryStream 中的数据。但是,packageStream.ToArray();
会在 MemoryStream 中创建数据的副本,因此在一段时间内,此例程的内存需求将是ZIP 存档。
我有一个 ZipArchive 对象,其中包含一个我正在修改的 XML 文件。然后我想 return 修改后的 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()
调用中引发 "Memory stream is not expandable" 异常。
任何人都可以解释我做错了什么,更新 ZipArchive 中现有文件的正确方法是什么?
显然,ZipArchive
想要扩展或调整 ZIP 存档流的大小。但是,您提供了 MemoryStream
和 固定 流长度(由于使用了构造函数 MemoryStream(byte[], bool)
,它创建了一个固定长度的内存流,该长度等于到提供给构造函数的数组的长度)。
由于 ZipArchive
想要扩展(或调整大小)流,提供可调整大小的 MemoryStream
(使用其无参数构造函数)。然后将原始文件数据复制到此 MemoryStream 并继续进行 ZIP 存档操作。
并且不要忘记将MemoryStreamread/write位置重置回0
后将原始文件数据复制到其中,否则ZipArchive 尝试从此流中读取 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();
已被放置在 内 ZipArchive 的 using
块中。在执行这一行时,ZipArchive 实例可能还没有将所有数据写入 MemoryStream,也许某些数据仍在一些内部缓冲区 and/or 可能推迟了一些 ZIP 数据结构的写入。
为了确保 ZipArchive 实际上已经将所有必要的数据完全写入 MemoryStream,移动 return packageStream.ToArray();
在 ZipArchive using
块之后。在其 using
块的末尾,ZipArchive 将被释放,这也将确保 ZipArchive 已将所有尚未写入的数据写入流。因此,在 ZipArchive 被清除后访问 MemoryStream 将产生完全更新的 ZIP 存档的完整数据。
旁注:仅对较小的 ZIP 文件执行此操作。 MemoryStream 显然会使用内部数据缓冲区(数组)来保存 MemoryStream 中的数据。但是,packageStream.ToArray();
会在 MemoryStream 中创建数据的副本,因此在一段时间内,此例程的内存需求将是ZIP 存档。