использование 7zip sdk для сжатия файла, но не может распаковать с помощью winrar или 7zip - PullRequest
4 голосов
/ 01 декабря 2011

Я скачал SDK 7zip с здесь .

Затем я использовал этот код для сжатия файла до 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();
    }
}

Я попробовал обе версии SDK 9.20 и 9.22 beta на сайте.

Сжатие, кажется, работает, чтобы сжать мой файл с: 1,6 МБ до 239 КБ.

Однако, если я использую WinRar или 7zip для распаковки. файл архива не распознается ими, ошибка вроде

«неизвестный архивный файл или поврежденный файл»

Есть идеи для этого?

Ответы [ 3 ]

5 голосов
/ 01 декабря 2011

вы смотрели пример проекта, включенного в SDK? Он находится в папке CS\7zip\Compress\LzmaAlone\ и содержит файл LmzaAlone.cs, в котором есть что-то, что кодирует файл. Он делает такие вещи, прежде чем записывает сжатые данные:

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

так что, похоже, сначала нужно записать несколько заголовков файлов, чтобы сообщить подробности о предстоящих данных сжатия.

если вы загрузите исходный код для 7Zip , то обнаружите, что в папке doc есть файл 7zFormat.txt, который содержит описание формата 7 файлов zip. Это может помочь вам создать действительные архивы.

3 голосов
/ 01 декабря 2011

Тот факт, что он работает на уровне Stream, предполагает, что он просто выполняет логику сжатия / распаковки lzm, а не создает реальный архив (архивом будет файл .zip или .7z). Аналогично использованию GZipStream или DeflateStream - архив не создается. Такие инструменты, как WinRar и 7zip, работают с архивами.

Я ожидаю, что в этом API есть еще один тип, который на самом деле создает архив, но будет ожидать больше информации, такой как имена файлов (он почти наверняка также примет несколько файлов / потоков).

2 голосов
/ 01 декабря 2011

Вы можете попробовать использовать 7zSharp wrapper или хотя бы проанализировать код упаковщиков, как все делается.

Код для сжатия файла (взят из 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);
  }
...