如何使用7z SDK压缩和解压文件

33
根据这个链接How do I create 7-Zip archives with .NET?,WOPR告诉我们如何使用7z SDK (http://www.7-zip.org/sdk.html) 压缩文件并使用LMZA(7z压缩算法)。
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();
      }
   }
}
但是如何解压它呢?
我尝试了:
private static void DecompressFileLZMA(string inFile, string outFile)
        {
            SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
            using (FileStream input = new FileStream(inFile, FileMode.Open))
            {
                using (FileStream output = new FileStream(outFile, FileMode.Create))
                {
                    coder.Code(input, output, input.Length, -1, null);
                    output.Flush();
                }
            }
        }

但是没有成功。

你有一个可行的例子吗?

谢谢。

PS: 根据另一段代码http://www.koders.com/csharp/fid43E85EE5AE7BB255C69D18ECC3288285AD67A4A4.aspx?s=zip+encoder#L5,看起来解码器需要一个文件开头的标头字典才能工作。由Koders生成的此文件不是7z存档文件。

   public static void Decompress(Stream inStream, Stream outStream)
    {
        byte[] properties = new byte[5];
        inStream.Read(properties, 0, 5);
        SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
        decoder.SetDecoderProperties(properties);
        long outSize = 0;
        for (int i = 0; i < 8; i++)
        {
            int v = inStream.ReadByte();
            outSize |= ((long)(byte)v) << (8 * i);
        }
        long compressedSize = inStream.Length - inStream.Position;
        decoder.Code(inStream, outStream, compressedSize, outSize, null);
    }

outSize的计算方式与其压缩方法相同。但如果要以其他方式计算输出大小,应该如何计算呢?


有任何异常吗?错误消息? - PVitt
我在LiteralDecoder类的Init()方法中的m_Coders[i].Init();处遇到了NullReferenceException。 - Djax
这里也有更完整的答案:https://dev59.com/FXVC5IYBdhLWcg3wpjB8#8775927 - Vando
3个回答

42

这个问题有点老了,但是谷歌没有提供令人满意的答案,所以我写下这篇文章,希望能帮助像我一样还在寻找答案的人。如果您查看 SDK 的 LMZAAlone 文件夹,那里有压缩和解压文件的代码。以此为例,似乎您需要将编码器属性和解压缩文件大小写入并读取到输出文件中:

private static void CompressFileLZMA(string inFile, string outFile)
    {
        SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();
        FileStream input = new FileStream(inFile, FileMode.Open);
        FileStream output = new FileStream(outFile, FileMode.Create);

        // Write the encoder properties
        coder.WriteCoderProperties(output);

        // Write the decompressed file size.
        output.Write(BitConverter.GetBytes(input.Length), 0, 8);

        // Encode the file.
        coder.Code(input, output, input.Length, -1, null);
        output.Flush();
        output.Close();
    }

    private static void DecompressFileLZMA(string inFile, string outFile)
    {
        SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
        FileStream input = new FileStream(inFile, FileMode.Open);
        FileStream output = new FileStream(outFile, FileMode.Create);

        // Read the decoder properties
        byte[] properties = new byte[5];
        input.Read(properties, 0, 5);

        // Read in the decompress file size.
        byte [] fileLengthBytes = new byte[8];
        input.Read(fileLengthBytes, 0, 8);
        long fileLength = BitConverter.ToInt64(fileLengthBytes, 0);

        coder.SetDecoderProperties(properties);
        coder.Code(input, output, input.Length, fileLength, null);
        output.Flush();
        output.Close();
    }
请注意,用这种方式创建的文件也可以被7zip程序提取,但不会保留它们的文件名或任何其他元数据。

我知道这是一个旧评论(和帖子),但我尝试了这段代码,它不起作用。当打开新的存档文件时,Windows 10会说它无效并且无法打开它。 - user1618054
我已经尝试了最新版本的7zip程序和库,它仍然可以正常工作。你说Windows 10显示无效,是指你正在尝试使用Windows资源管理器中内置的压缩文件查看器打开文件吗?我认为那个不支持7zip/LZMA。 - Fr33dan
原来Windows 10的存档查看器不支持.7z格式。您的代码可以正常工作,但是在提取归档文件时,文件扩展名似乎不存在,即使它包含在输入字符串中。该文件仍然有效,只是缺少扩展名;您如何纠正这个问题? - user1618054
3
问题答案中指出文件名和其他所有元数据都丢失了。这个问题和答案是关于使用7zip SDK解压文件的,与压缩文件以便使用7zip应用程序进行解压缩的问题超出了该问题的范围。我们创建的文件能够被该程序提取,这实际上是一个意外的好处。 - Fr33dan
1
这段代码有误,会导致归档文件损坏: output.Write(BitConverter.GetBytes(input.Length), 0, 8);请使用以下代码替换: for (int i = 0; i < 8; i++) { outputStream.WriteByte((Byte)(inputStream.Length >> (8 * i))); } - znelson
显示剩余3条评论

7

我需要使用LZMA压缩算法来在网络上传输图片,不确定它是否是最好的选择,但至少在我的生态系统中可以正常工作!因此,以下内容应该可以立即用于此目的。

using System;
using System.IO;
using SevenZip;

  public class LZMA{
    public static byte[] Compress(byte[] toCompress)
      {
        SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();

        using(MemoryStream input = new MemoryStream(toCompress))
        using(MemoryStream output = new MemoryStream()){

          coder.WriteCoderProperties(output);

          for (int i = 0; i < 8; i++) {
            output.WriteByte((byte)(input.Length >> (8 * i)));
          }

          coder.Code(input, output, -1, -1, null);
          return output.ToArray();
        }
      }

    public static byte[] Decompress(byte[] toDecompress)
    {
        SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();

        using(MemoryStream input = new MemoryStream(toDecompress))
        using(MemoryStream output = new MemoryStream()){

          // Read the decoder properties
          byte[] properties = new byte[5];
          input.Read(properties, 0, 5);


          // Read in the decompress file size.
          byte [] fileLengthBytes = new byte[8];
          input.Read(fileLengthBytes, 0, 8);
          long fileLength = BitConverter.ToInt64(fileLengthBytes, 0);

          coder.SetDecoderProperties(properties);
          coder.Code(input, output, input.Length, fileLength, null);

          return output.ToArray();
        }
    }
  }

1
这应该是被接受的答案 - 我找到的唯一有效的解决方案! - csstudent1418
1
这应该是被接受的答案 - 我找到的唯一有效的解决方案! - undefined
如果您使用此工具压缩文件,然后使用Windows 7z应用程序解压缩该文件,那么被压缩的文件将丢失其扩展名。 - Mario Codes
@MarioCodes 我真的很惊讶,它甚至能保留除文件内容以外的任何其他信息。这个解决方案是为了有一个知道预期结果的接收器而编写的,而不是用来在磁盘上保存压缩文件的方式。 - Dominic Grenier

4

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