如何使用.NET创建7-Zip压缩文件?

117

我该如何从我的C#控制台应用程序中创建7-Zip档案? 我需要能够使用常规的、广泛可用的7-Zip程序提取这些归档文件。


以下是根据此问题提供的示例对我的结果进行的分析

  • “运行”7z.exe - 这是最简单、最有效的方法,我可以确认它的工作效果不错。正如workmad3所提到的,我只需要确保在所有目标计算机上安装了7z.exe,这是我可以保证的。
  • 7Zip内存压缩 - 这是指在将cookie发送到客户端之前,在内存中压缩它们的方法; 这种方法似乎有些有希望。包装器方法(包装LZMA SDK)返回类型为byte[]。当我将byte[]数组写入文件时,我无法使用7-Zip解压缩它(File.7z不是支持的归档文件)。
  • 7zSharp包装器(在CodePlex上找到) - 这个包装器包装了7z exe / LZMA SDK。我从我的应用程序引用了该项目,并成功创建了一些归档文件,但我无法使用常规的7-Zip程序提取文件(File.7z不是支持的归档文件)。
  • 7Zip SDK即LZMA SDK - 我猜想我不够聪明,无法理解如何使用它(这就是我在这里发布的原因)... 有没有任何可行的代码示例可以演示如何创建一个能够被常规7zip程序解压缩的7zip归档文件呢?
  • CodeProject C# (.NET) Interface for 7-Zip Archive DLLs - 只支持从7zip归档文件中提取... 我需要创建它们!
  • SharpZipLib - 根据他们的FAQ,SharpZipLib不支持7zip。

  • 37
    请仅翻译文本内容,不要写出“这是从我的帖子中找到的链接,而不是谷歌翻译”的字样。这样做并不尊重那些花时间为您寻找解决方案的人们。 - Patrick Desjardins
    3
    我知道这篇帖子有点旧了,但我今天在研究中发现了一个名为SevenZipSharp的项目。http://sevenzipsharp.codeplex.com/ - Timmerz
    14
    未来的读者请注意,SevenZipSharp 似乎已被放弃。截至今天,最新的稳定版本(0.64)发布于2010年8月,有一些严重的多线程问题(根据错误报告)。自那以后只有很少的源代码提交 - Anttu
    12个回答

    86

    EggCafe 7Zip Cookie示例 这是一个使用7Zip DLL(动态链接库)进行压缩的示例,可以将cookie(浏览器中存储的信息)进行压缩。

    CodePlex 包装器 这是一个开源项目,它封装了7z的压缩功能。

    7Zip SDK 官方提供的7zip软件开发工具包(支持C、C++、C#和Java编程语言)。<---我的建议

    .Net 压缩库由SharpDevelop.net提供

    CodeProject 7zip 示例

    SharpZipLib 多种压缩方式


    完成了,我还添加了一个很有用的开源项目。 - Patrick Desjardins
    1
    LOL?把cookie换成字符串...一个文件或者其他的什么东西... 哈哈? - Patrick Desjardins
    3
    不,我只是想看看是否有人已经提供了一个可行的示例...感谢您的研究,但是您提供的链接都没有能够带我找到可行的解决方案。 - Seibar
    2
    我必须承认没有一个可以复制和粘贴的代码。SDK是拥有所有答案的那个,但需要一些时间和努力才能得到可行的东西。我理解你不想这样做。祝你有美好的一天。 - Patrick Desjardins
    4
    无论如何,我建议移除SharpDevelop/SharpZipLib的引用,因为两者都涉及到同一个内容,并且它们不支持7-Zip。Seibar明确要求使用7z。我也在寻找7z解决方案,因为SharpZipLib无法使用归档文件,而通过这个帖子找到了它。SharpZipLib是一个误导性的提示! - Onsokumaru
    显示剩余7条评论

    32
    如果您可以保证7-zip应用程序在所有目标机器上都被安装(并且在路径中),那么您可以通过调用命令行应用程序7z来卸载。虽不是最优雅的解决方案,但它是最简单的方法。

    8
    我们实际上将7z命令行实用程序与我们的二进制文件一起打包,并通过外壳调用它。对我们来说工作得非常好。 - David Mohundro

    26

    SevenZipSharp 是另一种解决方案。它可以创建7-zip档案...


    9
    这篇由markhor发布的帖子实际上是来自于SevenZipSharp项目的创建者。SevenZipSharp允许以编程方式访问7Zip dll,使其非常全面。相比之下,我发现LZMA SDK是低级别且难以理解的。相比之下,SevenZipSharp文档齐全、易于使用,并在其测试项目中有许多示例用法。使用这些示例,我可以快速地使用文件或内存进行压缩和解压缩。 - John Wigger
    4
    SevenZipSharp似乎已经被放弃了。请查看我在问题中之前的评论。 - Anttu
    SevenZipSharp 很慢。目前最推荐的解决方案是使用 Process.Start("7z.exe......)。 - klm_

    25
    这是一个使用C#中的SevenZip SDK的完整工作示例。它可以写入和读取由Windows 7zip应用程序创建的标准7zip文件。
    PS:之前的示例无法解压缩,因为它没有将所需的属性信息写入文件开头。
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using SevenZip.Compression.LZMA;
    using System.IO;
    using SevenZip;
    
    namespace VHD_Director
    {
        class My7Zip
        {
            public static void CompressFileLZMA(string inFile, string outFile)
            {
                Int32 dictionary = 1 << 23;
                Int32 posStateBits = 2;
                Int32 litContextBits = 3; // for normal files
                // UInt32 litContextBits = 0; // for 32-bit data
                Int32 litPosBits = 0;
                // UInt32 litPosBits = 2; // for 32-bit data
                Int32 algorithm = 2;
                Int32 numFastBytes = 128;
    
                string mf = "bt4";
                bool eos = true;
                bool stdInMode = false;
    
    
                CoderPropID[] propIDs =  {
                    CoderPropID.DictionarySize,
                    CoderPropID.PosStateBits,
                    CoderPropID.LitContextBits,
                    CoderPropID.LitPosBits,
                    CoderPropID.Algorithm,
                    CoderPropID.NumFastBytes,
                    CoderPropID.MatchFinder,
                    CoderPropID.EndMarker
                };
    
                object[] properties = {
                    (Int32)(dictionary),
                    (Int32)(posStateBits),
                    (Int32)(litContextBits),
                    (Int32)(litPosBits),
                    (Int32)(algorithm),
                    (Int32)(numFastBytes),
                    mf,
                    eos
                };
    
                using (FileStream inStream = new FileStream(inFile, FileMode.Open))
                {
                    using (FileStream outStream = new FileStream(outFile, FileMode.Create))
                    {
                        SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
                        encoder.SetCoderProperties(propIDs, properties);
                        encoder.WriteCoderProperties(outStream);
                        Int64 fileSize;
                        if (eos || stdInMode)
                            fileSize = -1;
                        else
                            fileSize = inStream.Length;
                        for (int i = 0; i < 8; i++)
                            outStream.WriteByte((Byte)(fileSize >> (8 * i)));
                        encoder.Code(inStream, outStream, -1, -1, null);
                    }
                }
    
            }
    
            public static void DecompressFileLZMA(string inFile, string outFile)
            {
                using (FileStream input = new FileStream(inFile, FileMode.Open))
                {
                    using (FileStream output = new FileStream(outFile, FileMode.Create))
                    {
                        SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
    
                        byte[] properties = new byte[5];
                        if (input.Read(properties, 0, 5) != 5)
                            throw (new Exception("input .lzma is too short"));
                        decoder.SetDecoderProperties(properties);
    
                        long outSize = 0;
                        for (int i = 0; i < 8; i++)
                        {
                            int v = input.ReadByte();
                            if (v < 0)
                                throw (new Exception("Can't Read 1"));
                            outSize |= ((long)(byte)v) << (8 * i);
                        }
                        long compressedSize = input.Length - input.Position;
    
                        decoder.Code(input, output, compressedSize, outSize, null);
                    }
                }
            }
    
            public static void Test()
            {
                CompressFileLZMA("DiscUtils.pdb", "DiscUtils.pdb.7z");
                DecompressFileLZMA("DiscUtils.pdb.7z", "DiscUtils.pdb2");
            }
        }
    }
    

    17
    请注意,这是纯粹的LZMA压缩/解压缩。7zip文件格式位于其之上,允许将多个文件与文件名/路径和其他文件元数据一起打包。 - redcalx
    2
    @redcalx是正确的。有人知道如何处理上层7zip吗?引用另一篇SO帖子会很好 :) - Christopher J Smith
    @Orwellophile,请问你可以解释一下密码应该放在哪里吗? - undefined

    9

    我使用了SDK。

    例如:

    using SevenZip.Compression.LZMA;
    private static void CompressFileLZMA(string inFile, string outFile)
    {
       SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();
    
       using (FileStream input = new FileStream(inFile, FileMode.Open))
       {
          using (FileStream output = new FileStream(outFile, FileMode.Create))
          {
              coder.Code(input, output, -1, -1, null);
              output.Flush();
          }
       }
    }
    

    11
    你将如何解压该文件?我尝试使用 SevenZip.Compression.LZMA.Decoder 进行相同的操作,并通过 Code(stream1, stream2, -1, -1, null) 进行调用,但这导致了一个来自框架的数据异常。 - Karsten
    你能给我一个使用SDK将文件压缩成归档文件的例子吗? - Vincent
    使用此工具尝试在Windows上解压缩,但出现异常并无法正常工作。 - Mario Codes

    3
     string zipfile = @"E:\Folderx\NPPES.zip";
     string folder = @"E:\TargetFolderx";
    
     ExtractFile(zipfile,folder);
    public void ExtractFile(string source, string destination)
            {
                // If the directory doesn't exist, create it.
                if (!Directory.Exists(destination))
                    Directory.CreateDirectory(destination);
    
                //string zPath = ConfigurationManager.AppSettings["FileExtactorEXE"];
              //  string zPath = Properties.Settings.Default.FileExtactorEXE; ;
    
                string zPath=@"C:\Program Files\7-Zip\7zG.exe";
    
                try
                {
                    ProcessStartInfo pro = new ProcessStartInfo();
                    pro.WindowStyle = ProcessWindowStyle.Hidden;
                    pro.FileName = zPath;
                    pro.Arguments = "x \"" + source + "\" -o" + destination;
                    Process x = Process.Start(pro);
                    x.WaitForExit();
                }
                catch (System.Exception Ex) { }
            }
    

    只需从源代码安装7 zip并将参数传递给方法即可。

    谢谢。请点赞答案。


    这对我在一个使用7za.exe的Windows服务中起作用。 - Marco Duindam

    2
    我使用这段代码。
                    string PZipPath = @"C:\Program Files\7-Zip\7z.exe";
                    string sourceCompressDir = @"C:\Test";
                    string targetCompressName = @"C:\Test\abc.zip";
                    string CompressName = targetCompressName.Split('\\').Last();
                    string[] fileCompressList = Directory.GetFiles(sourceCompressDir, "*.*");
    
                        if (fileCompressList.Length == 0)
                        {
                            MessageBox.Show("No file in directory", "Important Message");
                            return;
                        }
                        string filetozip = null;
                        foreach (string filename in fileCompressList)
                        {
                            filetozip = filetozip + "\"" + filename + " ";
                        }
    
                        ProcessStartInfo pCompress = new ProcessStartInfo();
                        pCompress.FileName = PZipPath;
                        if (chkRequestPWD.Checked == true)
                        {
                            pCompress.Arguments = "a -tzip \"" + targetCompressName + "\" " + filetozip + " -mx=9" + " -p" + tbPassword.Text;
                        }
                        else
                        {
                            pCompress.Arguments = "a -tzip \"" + targetCompressName + "\" \"" + filetozip + "\" -mx=9";
                        }
                        pCompress.WindowStyle = ProcessWindowStyle.Hidden;
                        Process x = Process.Start(pCompress);
                        x.WaitForExit();
    

    2
    在@Orwellophile的代码中,使用17.9MB的文本文件进行了一些额外的测试信息。
    如果将代码示例中的属性值“原样”使用,将对性能产生巨大的负面影响,需要14.16秒。

    将属性设置为以下内容可以在3.91秒内完成相同的工作(即存档将具有相同的容器信息,即您可以使用7zip提取和测试存档,但没有文件名信息)

    本机7zip 2秒钟。

    CoderPropID[] propIDs =  {
      //CoderPropID.DictionarySize,
      //CoderPropID.PosStateBits,
      //CoderPropID.LitContextBits,
      //CoderPropID.LitPosBits,
      //CoderPropID.Algorithm,
      //CoderPropID.NumFastBytes,
      //CoderPropID.MatchFinder,
      CoderPropID.EndMarker
    };
    object[] properties = {
      //(Int32)(dictionary),
      //(Int32)(posStateBits),
      //(Int32)(litContextBits),
      //(Int32)(litPosBits),
      //(Int32)(algorithm),
      //(Int32)(numFastBytes),
      //mf,
      eos
    };
    

    我使用本地的7zip和一个1.2GB的SQL备份文件(.bak)进行了另一个测试。
    7zip (最大压缩): 1分钟
    LZMA SDK (@Orwellophile 使用上述属性设置): 12:26 分钟 :-(
    输出文件大小大致相同。
    所以我想我自己会使用基于c/c++引擎的解决方案,即从c#中调用7zip可执行文件或使用squid-box/SevenZipSharp,它是7zip c/c++ dll文件的包装器,并似乎是SevenZipSharp的最新分支。我还没有测试过这个包装器,但我希望它能像本地的7zip一样表现出色。但是希望它能够压缩流,这显然是直接调用exe时无法实现的。否则,我想调用exe并没有什么优势。该包装器有一些附加依赖项,因此它不会使您的发布项目“更干净”。
    顺便说一下,.Net Core团队似乎考虑在.Core ver. 5中在system.io类中实现LZMA,这将是很棒的!(我知道这有点像评论而不是答案,但为了提供代码片段,它不能是评论)

    1

    安装名为SevenZipSharp.Interop的NuGet包。

    然后:

    SevenZipBase.SetLibraryPath(@".\x86\7z.dll");
    var compressor = new SevenZip.SevenZipCompressor();
    var filesToCompress = Directory.GetFiles(@"D:\data\");
    compressor.CompressFiles(@"C:\archive\abc.7z", filesToCompress);
    

    我尝试使用它将文件添加到现有的7z存档中,但得到了损坏的存档。 - Geograph

    1

    SharpCompress 在我看来是最聪明的压缩库之一。它支持LZMA(7-zip),易于使用且正在积极开发中。

    由于它已经支持LZMA流式传输,但遗憾的是目前仅支持7-zip存档读取。但是存档写入在他们的待办事项列表中(请参见自述文件)。对于未来的读者:请在此处查看当前状态:https://github.com/adamhathcock/sharpcompress/blob/master/FORMATS.md


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接