How to use the 7z SDK to compress and decompress a file
Asked Answered
N

4

33

According to this link How do I create 7-Zip archives with .NET? , WOPR tell us how to compress a file with LMZA (7z compression algorithm) using 7z SDK ( http://www.7-zip.org/sdk.html )

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();
      }
   }
}

But how to decompress it?

I try :

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();
                }
            }
        }

but without success.

Do you have a working example?

Thanks

PS: According to an other code http://www.koders.com/csharp/fid43E85EE5AE7BB255C69D18ECC3288285AD67A4A4.aspx?s=zip+encoder#L5 , it seems that the decoder needs a header, a dictionary at the beginning of the file to work. This file generated by Koders is not a 7z archive.

   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);
    }

The outSize is computed the same way than their Compress method. But how to compute the output size otherwise?

Niggerhead answered 4/10, 2011 at 10:14 Comment(3)
Are there any exceptions? Error messages?Snodgrass
I get a NullReferenceException on m_Coders[i].Init(); in Init() of class LiteralDecoderNiggerhead
There is also a little bit more complete answers here: https://mcmap.net/q/131478/-how-do-i-create-7-zip-archives-with-netSaltine
D
43

This question is a little old, but google fails to provide a satisfactory answer so this is for those like me still seeking it out. If you look into the LMZAAlone folder of the SDK there is code that compresses and decompresses files. Using it as an example it would seem you need to write and read the encoder properties and decompresses file size to your output file:

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();
    }

Note that the files created this way can be extracted by the 7zip program as well but will not retain their filename or any other metadata.

Devilry answered 22/12, 2011 at 15:12 Comment(8)
I know this is an old comment (and post), but I tried this code and it doesn't work. When opening new archive file, Windows 10 says it is invalid and won't open it.Overcapitalize
I tried it with the latest version of the 7zip program and library and it still works for me. What do you mean Windows 10 says it is invalid? Are you trying to open the file with the compressed file viewer built into Windows Explorer? I do not think that supports 7zip/LZMA.Devilry
Turns out Windows 10's archive viewer doesn't support .7z. Your code works, however, when extracting the archived file, the file extension does not appear to be present, even though it is included in the input string. The file is still valid, it's just missing the extension; how can you correct this?Overcapitalize
It is stated in the answer that the file name and all other metadata is lost. This question and answer is about decompressing files using the 7zip sdk, issues with compressing files to be decompressed with the 7zip application are outside the scope of this question. The fact that the files we created can be extracted with the program at all was an unexpected bonus.Devilry
This piece is incorrect and results in a broken archive: output.Write(BitConverter.GetBytes(input.Length), 0, 8); Replace it with this: for (int i = 0; i < 8; i++) { outputStream.WriteByte((Byte)(inputStream.Length >> (8 * i))); }Puritanical
Created file is corrupted and larger than original text file :|Kiethkiev
@Kiethkiev I'm not sure what you've done wrong without any code. I've just dusted this off created a small sample program to assess it in 2022. For me it still works in .NET 6.0 with the 22.01 version of the 7zip library exactly as described here. I can append the meat of my test sample code to the answer if you think it would help.Devilry
Not sure either, went back to deflate compressor and it working fine again :)Kiethkiev
L
7

I needed LZMA compression for sending images over network, not sure it's the best alternative but at least it works in my ecosystem! So here is something that should work right away for that purpose.

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();
        }
    }
  }
Let answered 16/4, 2020 at 1:32 Comment(3)
This should be the accepted answer - the only solution I found that worked!Vories
If you zip a file using this, and then you extract the file with windows 7z app the zipped file loses its extensionLetti
@MarioCodes I'm impressed it even keeps any other information than the file's contents to be honest. This solution was written with a receiver that knows what to expect in mind. Not as a way to save zipped files on disk.Let
I
4

I highly recommend managed-lzma:
https://github.com/weltkante/managed-lzma

It preserves file info and directory structure in file encoding.

Isobar answered 30/5, 2015 at 10:11 Comment(0)
I
0

Similar to @Dominic Grenier solution. Decompressor must know which properties to use to decompress the payload. This is your responsibility to serialize/deserialize them.

public static void 
Compress7Zip(this Stream input, Stream output) {
    var coder = new SevenZip.Compression.LZMA.Encoder();
    coder.WriteCoderProperties(output);
    output.WriteInt64(input.Length);
    coder.Code(input, output, -1, -1, null);
}

public static void 
Decompress7Zip(this Stream input, Stream output) {
    var coder = new SevenZip.Compression.LZMA.Decoder();
    var properties = new byte[5];
    input.Read(properties, 0, 5);
    var payloadLength = input.ReadInt64();
    coder.SetDecoderProperties(properties);
    coder.Code(input, output, input.Length, payloadLength, null);
}
Isobel answered 14/7, 2024 at 19:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.