【问题标题】:Unzip files programmatically in .net在 .net 中以编程方式解压缩文件
【发布时间】:2010-10-24 14:49:21
【问题描述】:

我正在尝试以编程方式解压缩压缩文件。

我尝试在 .NET 中使用 System.IO.Compression.GZipStream 类,但是当我的应用程序运行(实际上是单元测试)时,我得到了这个异常:

System.IO.InvalidDataException:GZip 标头中的幻数不正确。确保您传入的是 GZip 流。

我现在意识到.zip 文件与.gz 文件不同,GZipZip 不同。

但是,由于我可以通过手动双击压缩文件然后单击“提取所有文件”按钮来提取文件,因此我认为也应该有一种方法可以在代码中执行此操作。

因此,我尝试使用带有压缩文件路径的Process.Start() 作为输入。这会导致我的应用程序打开一个窗口,显示压缩文件中的内容。这一切都很好,但是该应用程序将安装在一个没有周围的服务器上单击“提取所有文件”按钮。

那么,我如何让我的应用程序提取压缩文件中的文件?

或者有其他方法吗?我更喜欢用代码来做,不下载任何第三方库或应用程序;安全部门对此不太感兴趣......

【问题讨论】:

  • 您的安全部门更愿意为某事编写自己的代码,而不是使用经过调试并被很多人关注的库?您可以使用库并“在代码中执行”(获取源代码并自己编译),但我认为重新发明轮子比使用久经考验的库所带来的任何安全问题更大。
  • @Jared - 当管理层在头脑中产生想法时......
  • 如果您获得第三方产品,安全部门的风险会更小。只需下载 dotnetzip 并将其重命名为“[插入公司名称].ziplibrary.dll”

标签: c# unzip


【解决方案1】:

借助 .NET 4.5,您现在可以使用 .NET 框架解压缩文件:

using System;
using System.IO;

namespace ConsoleApplication
{
  class Program
  {
    static void Main(string[] args)
    {
      string startPath = @"c:\example\start";
      string zipPath = @"c:\example\result.zip";
      string extractPath = @"c:\example\extract";

      System.IO.Compression.ZipFile.CreateFromDirectory(startPath, zipPath);
      System.IO.Compression.ZipFile.ExtractToDirectory(zipPath, extractPath);
    }
  }
}

以上代码直接取自微软文档:http://msdn.microsoft.com/en-us/library/ms404280(v=vs.110).aspx

ZipFile 包含在程序集 System.IO.Compression.FileSystem 中。 (感谢 nateirvin ......见下面的评论)。需要添加对框架程序集System.IO.Compression.FileSystem.dll的DLL引用

【讨论】:

  • 顺便说一句,ZipFile 包含在程序集 System.IO.Compression.FileSystem 中。
  • 这意味着你需要添加一个DLL引用到框架程序集System.IO.Compression.FileSystem.dll
  • .rar 文件怎么样。以上代码无法解压.rar文件。
  • 我在我的 asp.net 核心 web api 中尝试了这个,它读取第一个条目很好,但在第二个条目上它总是给出错误A local file header is corrupt。有没有这方面的?
  • @Aidan 很高兴知道,但如果可能的话,最好不要在 Mac/Linux 上使用 .NET。在没有的地方,这很有帮助。谢谢。
【解决方案2】:

适用于 .Net 4.5+

并不总是希望将未压缩的文件写入磁盘。作为 ASP.Net 开发人员,我将不得不摆弄权限来授予我的应用程序写入文件系统的权限。通过使用内存中的流,我可以避开所有这些并直接读取文件:

using (ZipArchive archive = new ZipArchive(postedZipStream))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
         var stream = entry.Open();
         //Do awesome stream stuff!!
    }
}

或者,您仍然可以通过调用ExtractToFile() 将解压缩文件写入磁盘:

using (ZipArchive archive = ZipFile.OpenRead(pathToZip))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        entry.ExtractToFile(Path.Combine(destination, entry.FullName));
    }
} 

要使用ZipArchive 类,您需要添加对System.IO.Compression 命名空间和System.IO.Compression.FileSystem 的引用。

【讨论】:

  • 真的需要 MSFT 到 4.5+ 才能添加原生解压缩器吗?
  • @JohnPeters GZipStream 已添加回 .Net 2.0 (msdn.microsoft.com/en-us/library/…)。但是,在内存中的存档中处理多个文件并不容易。新的 ZipArchive 对象非常适合。
  • 这是一个特别好的选择,因为它允许在不使用文件系统的情况下解压缩(在我的情况下,我使用的是嵌入式资源),而且它也不是第三种——派对延期。
  • 当我可以使用ZipFile.ExtractToDirectory(inputFile, outputDir);时,为什么还要使用foreach循环到ExtractToFile?第一种方法的优点是什么?
  • 在 .NET 4.6.1 中我无法从“System.IO.Compression.FileSystem”获取“ZipArchive”,有什么想法吗?
【解决方案3】:

我们已经在很多项目中成功使用了SharpZipLib。我知道它是第三方工具,但包含源代码,如果您选择在这里重新发明轮子,可以提供一些见解。

【讨论】:

  • 我尝试使用 SharpZipLib 并且效果很好。我想我得看看禁止第三方库和 apss 是严格的规则还是更多的指导方针。
  • 我不了解你的公司,但我的经验一直是,如果你写一个商业案例描述,这种规则有可能例外为什么你想要例外。指出与 DIY 相比节省的成本,以及可以检查来源的事实。作为后备方案,即使他们不允许您使用 dll,您通常也可以获得使用源代码的许可——然后只需自己编译它(或者至少是您实际需要使用的部分......)。
  • 您不必使用外部库来解压缩 zip 文件,您可以使用 System32 中的 Shell32。请看stackoverflow.com/a/43066281/948694
【解决方案4】:

免费,没有外部 DLL 文件。一切都在一个 CS 文件中。一个下载只是 CS 文件,另一个下载是一个非常容易理解的示例。今天刚试过,我不敢相信设置是多么简单。它在第一次尝试时有效,没有错误,没有任何东西。

https://github.com/jaime-olivares/zipstorer

【讨论】:

  • 说得太早了!我想立即从 http 下载流中扩充文件。这不起作用,因为它在流上使用了 Seek 操作 :( 好吧,感谢源代码,我现在可以编写自己的 ZipStream ...
  • 我的问题的最佳解决方案,因为我正在编写一个更新应用程序,并且我不能在提取过程中涉及任何 DLL,从那时起我也必须更新它们......这很好。谢谢!
【解决方案5】:

http://www.codeplex.com/DotNetZip 使用 DotNetZip 库

用于处理 zip 文件的类库和工具集。使用 VB、C# 或任何 .NET 语言轻松创建、提取或更新 zip 文件...

DotNetZip 可以在带有完整 .NET Framework 的 PC 上运行,也可以在使用 .NET Compact Framework 的移动设备上运行。在 VB、C# 或任何 .NET 语言或任何脚本环境中创建和读取 zip 文件...

如果您只想要一个更好的 DeflateStream 或 GZipStream 类来替换 .NET BCL 中内置的类,DotNetZip 也有。 DotNetZip 的 DeflateStream 和 GZipStream 可用于独立程序集,基于 Zlib 的 .NET 端口。这些流支持压缩级别并提供比内置类更好的性能。还有一个 ZlibStream 来完成集合(RFC 1950, 1951, 1952)...

【讨论】:

  • 嗯...但那是第三方库!
  • 你的观察力真好。除非您想花几个月的时间来实现自己的 Zip 文件阅读器,否则这是您的最佳选择。
  • 这个比 SharpZipLib 好很多
  • 你问我关于一个近 5 年的答案的问题。做一些研究。我相信你会找到答案的。
  • @PhilCooper 这是一个非常古老的问题,我建议使用内置的 System.IO.Compression.ZipFile。 IIRC 根据我在运行中生产数千个拉链的经验,我过去对 SharpZipLib 的体验非常糟糕。
【解决方案6】:
String ZipPath = @"c:\my\data.zip";
String extractPath = @"d:\\myunzips";
ZipFile.ExtractToDirectory(ZipPath, extractPath);

要使用 ZipFile 类,您必须在项目中添加对 System.IO.Compression.FileSystem 程序集的引用

【讨论】:

【解决方案7】:

这样就可以了System.IO.Compression.ZipFile.ExtractToDirectory(ZipName, ExtractToPath)

【讨论】:

    【解决方案8】:

    标准 zip 文件通常使用 deflate 算法。

    要在不使用第三方库的情况下提取文件,请使用 DeflateStream。您需要更多有关 zip 文件存档格式的信息,因为 Microsoft 仅提供压缩算法。

    您也可以尝试使用 zipfldr.dll。它是 Microsoft 的压缩库(发送到菜单中的压缩文件夹)。它似乎是一个 com 库,但没有记录。您也许可以通过实验让它为您工作。

    【讨论】:

    • 我正在尝试 DeflateStream 类。这次我得到 System.IO.InvalidDataException: Block length does not match with its supplement..
    • 正如我上面所说,微软只提供了算法。您还需要有关 zip 存档格式的信息。 en.wikipedia.org/wiki/ZIP_(file_format) 应该可以帮助您入门。有关更多详细信息的链接,请参阅页面底部的参考资料。
    • 我还偶然发现了 .NET 3.5 中的 System.IO.Packaging.Package。虽然它不是很直观,但看起来它可以解决问题。
    【解决方案9】:

    我使用它来压缩或解压缩多个文件。 Regex 的东西不是必需的,但我用它来更改日期戳并删除不需要的下划线。如果需要,我使用 Compress >> zipPath 字符串中的空字符串为所有文件添加前缀。另外,我通常会根据我正在做的事情注释掉 Compress() 或 Decompress()。

    using System;
    using System.IO.Compression;
    using System.IO;
    using System.Text.RegularExpressions;
    
    namespace ZipAndUnzip
    {
        class Program
        {
            static void Main(string[] args)
            {
                var directoryPath = new DirectoryInfo(@"C:\your_path\");
    
                Compress(directoryPath);
                Decompress(directoryPath);
            }
    
            public static void Compress(DirectoryInfo directoryPath)
            {
                foreach (DirectoryInfo directory in directoryPath.GetDirectories())
                {
                    var path = directoryPath.FullName;
                    var newArchiveName = Regex.Replace(directory.Name, "[0-9]{8}", "20130913");
                    newArchiveName = Regex.Replace(newArchiveName, "[_]+", "_");
                    string startPath = path + directory.Name;
                    string zipPath = path + "" + newArchiveName + ".zip";
    
                    ZipFile.CreateFromDirectory(startPath, zipPath);
                }
    
            }
    
            public static void Decompress(DirectoryInfo directoryPath)
            {
                foreach (FileInfo file in directoryPath.GetFiles())
                {
                    var path = directoryPath.FullName;
                    string zipPath = path + file.Name;
                    string extractPath = Regex.Replace(path + file.Name, ".zip", "");
    
                    ZipFile.ExtractToDirectory(zipPath, extractPath);
                }
            }
    
    
        }
    }
    

    【讨论】:

    • 这需要 dot net 4.5 - 就像其他回答 ZipFile 的人指出的那样,我仍在使用 3.5。
    【解决方案10】:

    您可以在 .NET 3.5 中使用 DeflateStream 完成所有操作。 .NET 3.5 中缺少的是处理用于组织压缩文件的文件头部分的能力。 PKWare 已发布此信息,您可以在创建所使用的结构后使用这些信息来处理 zip 文件。它不是特别繁重,在不使用 3rd 方代码的情况下构建工具是一种很好的做法。

    这不是一个简单的答案,但如果您愿意并且能够自己花时间,这是完全可行的。我在几个小时内编写了一个类来完成这项工作,我从中获得的是仅使用 .NET 3.5 压缩和解压缩文件的能力。

    【讨论】:

      【解决方案11】:

      来自here

      写入的压缩 GZipStream 对象 扩展名为 .gz 的文件可以 使用许多常见的解压缩 压缩工具;然而,这门课 本质上不提供 将文件添加到或 从 .zip 档案中提取文件。

      【讨论】:

        【解决方案12】:

        我今天发现了this one(在 NuGet 上解压缩包),因为我在 DotNetZip 中遇到了一个严重的错误,我意识到过去两年在 DotNetZip 上并没有做太多的工作。

        Unzip 包很精简,它为我完成了这项工作 - 它没有 DotNetZip 的错误。此外,它是一个相当小的文件,依赖于 Microsoft BCL 进行实际解压缩。我可以轻松地进行我需要的调整(以便能够在解压缩时跟踪进度)。我推荐它。

        【讨论】:

          【解决方案13】:

          来自嵌入资源:

          using (Stream _pluginZipResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(programName + "." + "filename.zip"))
          {
              using (ZipArchive zip = new ZipArchive(_pluginZipResourceStream))
              {
                  zip.ExtractToDirectory(Application.StartupPath);
              }
          }
          

          【讨论】:

            【解决方案14】:

            到目前为止,我一直在使用 cmd 进程来提取 .iso 文件,将其从服务器复制到临时路径中,然后提取到 U 盘上。最近我发现这与小于 10Gb 的 .iso 完美配合。对于像 29Gb 这样的 iso,这种方法会以某种方式卡住。

                public void ExtractArchive()
                {
                    try
                    {
            
                        try
                        {
                            Directory.Delete(copyISOLocation.OutputPath, true); 
                        }
                        catch (Exception e) when (e is IOException || e is UnauthorizedAccessException)
                        {
                        }
            
                        Process cmd = new Process();
                        cmd.StartInfo.FileName = "cmd.exe";
                        cmd.StartInfo.RedirectStandardInput = true;
                        cmd.StartInfo.RedirectStandardOutput = true;
                        cmd.StartInfo.CreateNoWindow = true;
                        cmd.StartInfo.UseShellExecute = false;
                        cmd.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            
                        //stackoverflow
                        cmd.StartInfo.Arguments = "-R";
            
                        cmd.Disposed += (sender, args) => {
                            Console.WriteLine("CMD Process disposed");
                        };
                        cmd.Exited += (sender, args) => {
                            Console.WriteLine("CMD Process exited");
                        };
                        cmd.ErrorDataReceived += (sender, args) => {
                            Console.WriteLine("CMD Process error data received");
                            Console.WriteLine(args.Data);
                        };
                        cmd.OutputDataReceived += (sender, args) => {
                            Console.WriteLine("CMD Process Output data received");
                            Console.WriteLine(args.Data);
                        };
            
                        //stackoverflow
            
            
                        cmd.Start();
            
                        cmd.StandardInput.WriteLine("C:");
                        //Console.WriteLine(cmd.StandardOutput.Read());
                        cmd.StandardInput.Flush();
            
                        cmd.StandardInput.WriteLine("cd C:\\\"Program Files (x86)\"\\7-Zip\\");
                        //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
                        cmd.StandardInput.Flush();
            
                        cmd.StandardInput.WriteLine(string.Format("7z.exe x -o{0} {1}", copyISOLocation.OutputPath, copyISOLocation.TempIsoPath));
                        //Console.WriteLine(cmd.StandardOutput.ReadToEnd());
                        cmd.StandardInput.Flush();
                        cmd.StandardInput.Close();
                        cmd.WaitForExit();
                        Console.WriteLine(cmd.StandardOutput.ReadToEnd());
                        Console.WriteLine(cmd.StandardError.ReadToEnd());
            

            【讨论】:

              【解决方案15】:

              你可以使用Info-unzip命令行cod。你只需要从Info-unzip官网下载unzip.exe即可。

               internal static void Unzip(string sorcefile)
                  {
                      try
                      {
                          AFolderFiles.AFolderFilesDelete.DeleteFolder(TempBackupFolder); // delete old folder   
                          AFolderFiles.AFolderFilesCreate.CreateIfNotExist(TempBackupFolder); // delete old folder   
                         //need to Command command also to export attributes to a excel file
                          System.Diagnostics.Process process = new System.Diagnostics.Process();
                          System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
                          startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; // window type
                          startInfo.FileName = UnzipExe;
                          startInfo.Arguments = sorcefile + " -d " + TempBackupFolder;
                          process.StartInfo = startInfo;
                          process.Start();
                          //string result = process.StandardOutput.ReadToEnd();
                          process.WaitForExit();
                          process.Dispose();
                          process.Close();
                      }
                      catch (Exception ex){ throw ex; }
                  }        
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-03-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-11-23
                相关资源
                最近更新 更多