4

I downloaded the SDK 7zip from here.

Then I used this code to compress a file to 7zip:

private static void CompressFileLZMA(string inFile, string outFile)
{
    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();
    }
}

I tried both the SDK versions 9.20 and 9.22 beta on the site.

The compression seems working to compress my file from: 1.6 MB to 239 KB.

However, if I use WinRar or 7zip to decompress. the archive file is not recognized by them, the error is like

"unknown archive file or damaged file"

Any idea for this?

abatishchev
  • 98,240
  • 88
  • 296
  • 433
olidev
  • 20,058
  • 51
  • 133
  • 197

3 Answers3

5

have you looked at the example project included with the SDK? It is in the CS\7zip\Compress\LzmaAlone\ folder and it contains a file LmzaAlone.cs which has some stuff which encodes a file. It does things like this before it writes out the compressed data:

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

Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
encoder.SetCoderProperties(propIDs, properties);
encoder.WriteCoderProperties(outStream);
if (trainStream != null)
{
    CDoubleStream doubleStream = new CDoubleStream();
    doubleStream.s1 = trainStream;
    doubleStream.s2 = inStream;
    doubleStream.fileIndex = 0;
    inStream = doubleStream;
    long trainFileSize = trainStream.Length;
    doubleStream.skipSize = 0;
    if (trainFileSize > dictionary)
        doubleStream.skipSize = trainFileSize - dictionary;
    trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
    encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
}
// only now does it write out the compressed data:
encoder.Code(inStream, outStream, -1, -1, null);

so it looks like you need to write out a few file headers first to give the details about the compression data that is coming.

if you download the source for 7Zip then you will find that in the doc folder there is a file 7zFormat.txt which contains a description of the format of the 7 zip files. This might help you create valid archives.

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
3

The fact that it is operating at the Stream level suggests it is just doing the lzm compress/decompress logic, and is not building an actual archive (an archive would be a .zip or .7z file). Similar to using GZipStream or DeflateStream - it isn't producing an archive. Tools like WinRar and 7zip work on archives.

I expect there is another type in that API that actually produces an archive, but will expect more information such as file names (it will almost certainly accept multiple files/streams, too).

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I simply called it like this: CompressFileLZMA("CompressionTest.pdb", "CompressionTestabc.7z"); – olidev Dec 01 '11 at 09:53
  • @devn the point being that CompressFileLZMA is *your* method and *your* method is not writing out a valid archive, it is simply writing out the compressed data stream to the file. You could read that data stream in and decompress it using the api, but it won't produce a valid *Archive file* without some extra information such as file headers etc. This might be useful if you wanted to compress data which would not look like an archive that could be opened in 7Zip, but your program could read. but to be able to read the data in 7Zip or similar you need to produce a valid archive – Sam Holder Dec 01 '11 at 10:18
2

You can try to use 7zSharp wrapper or at least analyze wrappers code how everything is done.

Code to compress file(taken from 7zSharp):

  public void EncodeSingleFile(string inFile, string outFile)
  {
     using (FileStream inStream = new FileStream(inFile, FileMode.Open, FileAccess.Read))
     {
        using (FileStream outStream = new FileStream(outFile, FileMode.OpenOrCreate, FileAccess.Write))
        {
           EncodeSingleFile(inStream, outStream);
        }
     }
  }

  public void EncodeSingleFile(FileStream inStream, FileStream outStream)
  {
     bool eos = false;
     Int32 dictionary = 1 << 21;
     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";

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

     Encoder encoder = new Encoder();
     encoder.SetCoderProperties(propIDs, properties);
     encoder.WriteCoderProperties(outStream);
     Int64 fileSize = inStream.Length;
     for (int i = 0; i < 8; i++)
     {
        outStream.WriteByte((Byte) (fileSize >> (8*i)));
     }
     encoder.Code(inStream, outStream, -1, -1, null);
  }
Renatas M.
  • 11,694
  • 1
  • 43
  • 62
  • yes, it helps. With this wrapper, I can create a 7zip file successfully. However, there are two issues: 1. I can only decompress it using 7zip shell installed from 7-zip.org, can not decompress with unrar. is that possible if I set some parameters and it will work with unrar as well? 2. after compressing in 7zip file, the archive file name is not as original: e.g: I have test.abc, then 7zip it as: compressed7.7z then the archive file inside is "compressed" without the extension. It should be test.abc inside the 7zip. How can I achieve this? thanks in advance. – olidev Dec 01 '11 at 11:06
  • I think this is another issue, I posted it here: http://stackoverflow.com/questions/8340636/using-7zip-sdk-to-compress-a-file-but-the-archive-file-is-not-as-original-and-c – olidev Dec 01 '11 at 11:29
  • do you have any idea if there is a wrapper like this using 7zip sdk to compress a directory as well? – olidev Dec 01 '11 at 15:00
  • looks like that wrapper has method for that `EncodeFromDirectory` - this is shown in 7zSharp main page. – Renatas M. Dec 01 '11 at 15:06
  • ok one simple question: why you want to use 7zip archive? And why have reference to dll is so bad? – Renatas M. Dec 01 '11 at 20:57
  • the requirement of the customer is to compress it as a 7zip. I want to get rid of dll file. I would like to deliver the exe only. – olidev Dec 01 '11 at 21:06