首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >System.IO.Compression.ZipArchive内存管理

System.IO.Compression.ZipArchive内存管理
EN

Stack Overflow用户
提问于 2014-12-12 15:08:34
回答 1查看 3.3K关注 0票数 3

在.Net 4.5中,System.IO.Compression.ZipArchive类得到一些更新。

就像这里的可读性(http://msdn.microsoft.com/en-us/magazine/jj133817.aspx)一样,它现在应该做“典型的操作不需要将整个归档文件读入内存”。

为了进行测试,我尝试压缩10个文件,每个文件大小为200 10。

如果您使用此代码创建新的zip档案(在整个过程中内存使用率较低),这是很好的:

代码语言:javascript
复制
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);
    }
  }              
}

现在我想要向这个归档文件添加新的条目。我保留代码原样,然后再次运行它。(使用根目录中的新文件)如果我查看文档,就会看到“只允许创建新的归档条目”,这是我想要的。所以我的代码应该没问题。

现在的结果是:

  1. 存档中的文件表被覆盖(只列出新文件)。
  2. 档案文件的大小增加了(就像旧的文件还在里面一样)。
  3. 档案被破坏了。你可以打开它,但你不能去除内容。

如果我将ZipArchiveMode更改为"ZipArchiveMode.Update“,它的工作方式与预期的一样,但只适用于小文件。像my这样的文件会抛出内存不足的异常,因为完整的归档文件被加载到内存中.

我现在的问题是:是我做错了,这是一个错误,还是一个设计缺陷?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-12-12 18:22:11

您编写的代码导致ZipArchive类在上一个归档的末尾编写一个全新的存档,这当然会破坏文件。

所需的方法是在创建原始文件时将原始存档复制到新文件中,然后用新的文件替换原始存档。例如:

代码语言:javascript
复制
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慢。当您使用update模式时,ZipArchive类会将整个归档文件读入内存(正如您已经注意到的那样),然后当您关闭它时,它会重新压缩并将所有内容写回内存。

上面的计算基本上是完全相同的,但只是使用磁盘作为中间存储,而不是内存。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27446495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档