在.net中以编程方式解压缩文件


221

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

我曾尝试System.IO.Compression.GZipStream在.NET中使用该类,但是当我的应用运行(实际上是单元测试)时,出现此异常:

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

我现在意识到.zip文件与文件并不相同.gz,并且与GZip也不相同Zip

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

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

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

还是有其他方法可以做到?我更喜欢用代码来实现,而无需下载任何第三方库或应用程序;安全部门对此不太看好...


12
您的安全部门比您使用经过调试并可能有很多目光的库来编写自己的代码要快乐得多?您可以使用一个库并“在代码中完成”(获取源代码并自己进行编译),但我认为,与使用经过尝试的真实库所带来的任何安全性问题相比,重新发明轮子是一个更大的问题。
Jared Updike

10
@Jared-当管理层想到一个主意时
史蒂文·埃弗斯

4
如果您获得第三方产品,则安全部门的风险会降低。只需下载dotnetzip并将其重命名为“ [插入公司名称] .ziplibrary.dll”
西蒙

Answers:


59

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


3
我尝试使用SharpZipLib,它工作正常。我猜我将不得不看看禁止第三方libs和apss是一项严格的规定还是更多的准则。
Petteri发

9
我不了解您的公司,但是我的经验一直是,如果您编写了一个有关为什么要例外的商业案例描述,就有可能对该类规则产生例外。指出节省成本与DIY的关系,以及可以检查来源的事实。作为后备,即使他们不允许您使用dll,您也通常会获得使用源的许可-然后自己进行编译(或至少编译您实际需要使用的部分...)。
RolandTumble

您不必使用外部库来解压缩zip文件,可以使用System32中的Shell32。请参阅stackoverflow.com/a/43066281/948694
arturn

490

使用.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);
    }
  }
}

上面的代码直接来自Microsoft的文档:http : //msdn.microsoft.com/zh-cn/library/ms404280(v=vs.110).aspx

ZipFile包含在程序集中System.IO.Compression.FileSystem。(感谢nateirvin ...请参阅下面的评论)


118
BTW,ZipFile包含在程序集中System.IO.Compression.FileSystem
nateirvin

73
这意味着您需要向框架程序集添加DLL引用System.IO.Compression.FileSystem.dll
克里斯·希夫豪尔

.rar文件呢?上面的代码无法提取.rar文件。
Raghu

1
我在我的asp.net核心网络api中尝试了此操作,它的第一个条目读得很好,但是在第二个条目上总是给出error A local file header is corrupt。虽然这样吗?
SoftSan

与@SoftSan相同。我也有那个错误。该怎么办?
丰富

101

对于.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


8
MSFT直到4.5+才真正添加了本地解压缩器吗?
约翰·彼得斯

2
@JohnPeters GZipStream被添加回.Net 2.0(msdn.microsoft.com/en-us/library/…)。但是,使用内存中的存档中的多个文件并不容易。新ZipArchive对象非常合适。
史诗先生

1
这是一个特别好的选择,因为它允许不使用文件系统进行解压缩(在我的情况下,我正在使用嵌入式资源),并且它也不是第三方扩展。
2015年

1
当我只能使用第一种方法时,为什么要使用foreach循环?ExtractToFileZipFile.ExtractToDirectory(inputFile, outputDir);
蓬松的机器人

1
在.NET 4.6.1中,我无法从“ System.IO.Compression.FileSystem”获得“ ZipArchive”,有任何想法吗?
拉维·阿南德

55

免费,没有外部DLL文件。一切都在一个CS文件中。一个下载只是CS文件,另一个下载是一个非常容易理解的示例。今天就尝试过,我简直不敢相信安装过程多么简单。第一次尝试就可以了,没有错误,没什么。

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


发言太早了!我想立即从http下载流中添加文件。这是行不通的,因为它在流上使用Seek操作:(好吧,由于源代码,我现在可以编写自己的ZipStream ...
oyophant 2014年

最好的解决方案,因为我正在编写一个更新器应用程序,并且在提取过程中我不能涉及任何DLL,因为那时我也必须更新那些DLL .... good。谢谢!
Niklas

27

使用位于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也可以。基于Zlib的.NET端口,DotNetZip的DeflateStream和GZipStream可在独立程序集中使用。这些流支持压缩级别,并提供比内置类更好的性能。还有一个ZlibStream可以完成设置(RFC 1950,1951,1952)...


1
嗯...但是那是第三方图书馆!
佩特里

30
你真是很细心 除非您想花几个月的时间来实现自己的Zip文件阅读器,否则这是您的最佳选择。
山姆·艾克斯

这一个是更好的方式比SharpZipLib
库格尔

5
您问我有关将近5年的答案的问题。做一些研究。我相信您会找到答案。
山姆Ax 2014年

2
@PhilCooper这是一个非常老的问题,我建议使用内置的System.IO.Compression.ZipFile。IIRC过去,根据我在飞行中产生数千个拉链的经验,我在SharpZipLib方面的经历非常糟糕。
库格尔


2

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

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

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


我正在尝试DeflateStream类。这一次,我得到System.IO.InvalidDataException:块长度不与它的补匹配..
Petteri发

就像我上面说的,Microsoft只提供了该算法。您还将需要有关zip存档格式的信息。en.wikipedia.org/wiki/ZIP_(file_format)应该可以帮助您入门。有关更多详细信息的链接,请参见页面底部的参考。
肯尼斯·科克伦

2
我还偶然发现了.NET 3.5中的System.IO.Packaging.Package。尽管它不是很直观,但看起来可以解决问题。
肯尼斯·科克伦

2

我用它来压缩或解压缩多个文件。正则表达式不是必需的,但是我用它来更改日期戳并删除不想要的下划线。如果需要,我使用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);
            }
        }


    }
}

这需要网点4.5-只是一个注释,就像其他回答ZipFile的人指出的那样,我仍在使用3.5。
2014年


1

这里

可以使用许多常用的压缩工具对写入扩展名为.gz的文件中的压缩GZipStream对象进行解压缩。但是,此类本身并未提供向.zip归档文件添加文件或从中提取文件的功能。


1

您可以使用DeflateStream在.NET 3.5中完成所有操作。.NET 3.5缺少的是能够处理用于组织压缩文件的文件头部分。PKWare已发布了此信息,您可以在创建使用的结构后使用该信息来处理zip文件。它并不是特别繁琐,并且是不使用第3方代码的工具构建的良好实践。

这不是一个单一的答案,但是如果您愿意并且能够自己花费时间,那么它是完全可行的。我编写了一个类在几个小时内完成此操作,而我得到的是仅使用.NET 3.5压缩和解压缩文件的能力。


0

自从我在DotNetZip中遇到一个硬错误以来,我今天就找到了这个(NuGet上的Unzip软件包),并且我意识到在过去的两年中在DotNetZip上确实没有做太多的工作。

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


0

来自嵌入资源:

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

0

到目前为止,我一直使用cmd进程来提取.iso文件,将其复制到服务器的临时路径中,然后通过USB记忆棒提取。最近,我发现这与小于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());

0

您可以使用Info-unzip命令行编码。您只需从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; }
    }        
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.