【问题标题】:Compressing / Decompressing Folders & Files压缩/解压缩文件夹和文件
【发布时间】:2010-09-05 05:39:07
【问题描述】:

有没有人知道在 C# 中快速压缩或解压缩文件和文件夹的好方法?可能需要处理大文件。

【问题讨论】:

    标签: c# .net file compression


    【解决方案1】:

    .Net 2.0 框架命名空间System.IO.Compression 支持 GZip 和 Deflate 算法。这里有两种方法可以压缩和解压缩可以从文件对象中获取的字节流。您可以在以下方法中将GZipStream 替换为DefaultStream 以使用该算法。但是,这仍然存在处理使用不同算法压缩的文件的问题。

    public static byte[] Compress(byte[] data)
    {
        MemoryStream output = new MemoryStream();
    
        GZipStream gzip = new GZipStream(output, CompressionMode.Compress, true);
        gzip.Write(data, 0, data.Length);
        gzip.Close();
    
        return output.ToArray();
    }
    
    public static byte[] Decompress(byte[] data)
    {
        MemoryStream input = new MemoryStream();
        input.Write(data, 0, data.Length);
        input.Position = 0;
    
        GZipStream gzip = new GZipStream(input, CompressionMode.Decompress, true);
    
        MemoryStream output = new MemoryStream();
    
        byte[] buff = new byte[64];
        int read = -1;
    
        read = gzip.Read(buff, 0, buff.Length);
    
        while (read > 0)
        {
            output.Write(buff, 0, read);
            read = gzip.Read(buff, 0, buff.Length);
        }
    
        gzip.Close();
    
        return output.ToArray();
    }
    

    【讨论】:

      【解决方案2】:

      我一直使用 SharpZip 库。

      Here's a link

      【讨论】:

      • 注意:几年前我在 SharpZip 代码中发现了一个 int overflow 错误,它导致它在恰好具有正确值组合的随机文件上失败。不确定这是否得到修复,但我从内存中将 SharpZip 源中的 int 变量更改为 long 以避免溢出。 我将不得不尝试找到我的旧固定 SharpZip 代码并检查它是否与最新的匹配
      【解决方案3】:

      正如汤姆指出的那样,您可以使用3rd-party library such as SharpZip

      另一种方法(不使用第 3 方)是使用 Windows Shell API。您需要在 C# 项目中设置对 Microsoft Shell 控件和自动化 COM 库的引用。 Gerald Gibson 有一个例子:

      Internet Archive's copy of the dead page

      【讨论】:

        【解决方案4】:

        从 .Net 1.1 开始,唯一可用的方法是进入 java 库。

        Using the Zip Classes in the J# Class Libraries to Compress Files and Data with C#

        不确定这在最近的版本中是否有所改变。

        【讨论】:

          【解决方案5】:

          我的回答是闭上眼睛,选择DotNetZip。它已经过大型社区的测试。

          【讨论】:

            【解决方案6】:

            GZipStream 是一个非常好的实用工具。

            【讨论】:

              【解决方案7】:

              这在 java 中很容易做到,如上所述,您可以从 C# 访问 java.util.zip 库。有关参考,请参阅:

              java.util.zip javadocs
              sample code

              我不久前使用它对文件夹结构进行深度(递归)压缩,但我认为我从未使用过解压缩。如果我有这么大的动力,我可能会拉出该代码并稍后将其编辑到这里。

              【讨论】:

                【解决方案8】:

                另一个不错的选择也是DotNetZip

                【讨论】:

                  【解决方案9】:

                  您可以使用此方法创建 zip 文件:

                  public async Task<string> CreateZipFile(string sourceDirectoryPath, string name)
                  {
                      var path = HostingEnvironment.MapPath(TempPath) + name;
                      await Task.Run(() =>
                      {
                          if (File.Exists(path)) File.Delete(path);
                          ZipFile.CreateFromDirectory(sourceDirectoryPath, path);
                      });
                      return path;
                  }
                  

                  然后您可以使用以下方法解压缩 zip 文件:

                  1- 此方法适用于 zip 文件路径

                  public async Task ExtractZipFile(string filePath, string destinationDirectoryName)
                  {
                      await Task.Run(() =>
                      {
                          var archive = ZipFile.Open(filePath, ZipArchiveMode.Read);
                          foreach (var entry in archive.Entries)
                          {
                              entry.ExtractToFile(Path.Combine(destinationDirectoryName, entry.FullName), true);
                          }
                          archive.Dispose();
                      });
                  }
                  

                  2- 此方法适用于 zip 文件流

                  public async Task ExtractZipFile(Stream zipFile, string destinationDirectoryName)
                  {
                      string filePath = HostingEnvironment.MapPath(TempPath) + Utility.GetRandomNumber(1, int.MaxValue);
                      using (FileStream output = new FileStream(filePath, FileMode.Create))
                      {
                          await zipFile.CopyToAsync(output);
                      }
                      await Task.Run(() => ZipFile.ExtractToDirectory(filePath, destinationDirectoryName));
                      await Task.Run(() => File.Delete(filePath));
                  }
                  

                  【讨论】: