这里可读(http://msdn.microsoft.com/en-us/magazine/jj133817.aspx)它现在应该“典型的操作不需要将整个存档读入内存”。
为了进行测试,我尝试压缩10个文件,每个文件大小为200MB。
如果您使用此代码创建新的zip存档(在整个过程中内存使用率较低),则此方法很有用:
for (int directoryGroupIndex = 0; directoryGroupIndex < directoryGroups.Count; directoryGroupIndex++)
{
String directoryGroupKey = directoryGroups.Keys.ElementAt(directoryGroupIndex);
FileInfo[] directoryGroup = directoryGroups[directoryGroupKey];
String archiveFileName = String.Format("Readed Logfiles{0}", archiveFileExtension);
String archiveFileFullName = Path.Combine(directoryGroupKey, archiveFileName);
FileInfo archiveFile = new FileInfo(archiveFileFullName);
using (FileStream archiveFileStream = new FileStream(archiveFile.FullName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
using (ZipArchive archive = new ZipArchive(archiveFileStream, ZipArchiveMode.Create, false))
{
for (int directoryGroupFileIndex = 0; directoryGroupFileIndex < directoryGroup.Length; directoryGroupFileIndex++)
{
FileInfo file = directoryGroup[directoryGroupFileIndex];
String archiveEntryName = file.Name;
String archiveEntryPath = DateTime.Now.ToString("yyyy-MM-dd");
String archiveEntryFullName = Path.Combine(archiveEntryPath, archiveEntryName);
ZipArchiveEntry archiveEntry = archive.CreateEntryFromFile(file.FullName, archiveEntryFullName, CompressionLevel.Optimal);
}
}
}
现在我想添加新的条目到此存档。我保留我的代码并再次运行它。 (在根目录中有新文件)如果我查看文档,我读了“只允许创建新的存档条目”,这就是我想要的。所以我的代码应该没问题。
现在的结果是:
将覆盖存档中的文件表(仅列出新文件)。
存档文件的大小已经增长(就像旧文件仍在那里一样)。
存档已损坏。您可以打开它,但不能解压缩内容。
如果我将ZipArchiveMode更改为“ZipArchiveMode.Update”,它会按预期工作,但只能使用小文件。 像my这样的文件会抛出一个内存不足的异常,因为整个存档被加载到内存中。
我现在的问题是:我做错了,这是一个错误还是一个设计漏洞?
答案 0 :(得分:5)
您编写的代码导致ZipArchive
类在您之前的代码末尾写入一个全新的存档,这当然会破坏该文件。
执行所需操作的方法是在创建原始存档时将其复制到新文件中,然后将原始存档替换为新文件。例如:
string tempFile = Path.GetTempFileName();
using (ZipArchive original =
new ZipArchive(File.Open(archiveFileStream, FileMode.Open), ZipArchiveMode.Read))
using (ZipArchive newArchive =
new ZipArchive(File.Open(tempFile, FileMode.Create), ZipArchiveMode.Create))
{
foreach (ZipArchiveEntry entry in original.Entries)
{
ZipArchiveEntry newEntry = newArchive.Create(entry.FullName);
using (Stream source = entry.Open())
using (Stream destination = newEntry.Open())
{
source.CopyTo(destination);
}
}
for (int directoryGroupFileIndex = 0;
directoryGroupFileIndex < directoryGroup.Length;
directoryGroupFileIndex++)
{
FileInfo file = directoryGroup[directoryGroupFileIndex];
String archiveEntryName = file.Name;
String archiveEntryPath = DateTime.Now.ToString("yyyy-MM-dd");
String archiveEntryFullName = Path.Combine(archiveEntryPath, archiveEntryName);
ZipArchiveEntry archiveEntry = newArchive.CreateEntryFromFile(
file.FullName, archiveEntryFullName, CompressionLevel.Optimal);
}
}
File.Delete(archiveFileStream);
File.Move(tempFile, archiveFileStream);
请注意,这实际上并不比ZipArchiveMode.Update
慢。当您使用更新模式时,ZipArchive
类将整个存档读入内存(如您所述),然后当您关闭它时,它会重新压缩并将所有内容写回。
以上基本上完全相同的计算,但只是使用磁盘作为中间存储而不是内存。