使用7zip SDK压缩文件,但无法使用WinRAR或7zip进行解压缩。

4
我从这里下载了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 MB压缩到239 KB。

但是,如果我使用WinRar或7zip进行解压缩,存档文件无法被它们识别,错误消息如下:

"未知的存档文件或已损坏的文件"

有什么想法吗?

3个回答

5

你是否看过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 的文件,其中包含了 7Zip 文件格式的描述。这可能有助于你创建有效的归档文件。


+1 对于标题,很可能是 OP 忘记放它们了。 - oleksii

3
它在“Stream”级别运行的事实表明它只是执行lzm压缩/解压逻辑,并没有构建实际的归档文件(归档文件将是.zip或.7z文件)。类似于使用“GZipStream”或“DeflateStream” - 它不会生成归档文件。像WinRar和7zip这样的工具适用于归档文件。
我预计在该API中还有另一种类型实际上会生成一个存档文件,但需要更多信息,例如文件名(它也几乎肯定会接受多个文件/流)。

我只是这样调用它的:CompressFileLZMA("CompressionTest.pdb", "CompressionTestabc.7z"); - olidev
@devn,重点是CompressFileLZMA是您的方法,而且您的方法并没有写出有效的存档文件,它只是将压缩数据流写入文件中。您可以使用API读取该数据流并进行解压缩,但如果没有一些额外的信息(如文件头等),它将不会生成一个有效的存档文件。如果您想要压缩数据,这可能很有用,这些数据看起来不像可以在7Zip中打开的存档,但是您的程序可以读取。但是,要能够在7Zip或类似软件中读取数据,您需要生成一个有效的存档。 - Sam Holder

2
你可以尝试使用7zSharp包装器,或者至少分析包装器代码以了解所有操作的方式。
压缩文件所需代码(来自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);
  }

是的,它很有用。有了这个包装器,我可以成功地创建一个7zip文件。然而,有两个问题:1. 我只能使用从7-zip.org安装的7zip shell解压缩它,不能使用unrar解压缩。如果我设置一些参数,是否可能也能与unrar一起使用?2. 在7zip文件中压缩后,归档文件名不像原来那样:例如:我有test.abc,然后将其7zip为:compressed7.7z,然后归档文件内部是没有扩展名的“compressed”。它应该是7zip中的test.abc。我该如何实现这一点?提前致谢。 - olidev
我认为这是另一个问题,我在这里发布了:http://stackoverflow.com/questions/8340636/using-7zip-sdk-to-compress-a-file-but-the-archive-file-is-not-as-original-and-c - olidev
你知道是否有像这样使用7zip SDK来压缩目录的封装器吗? - olidev
看起来那个包装器有一个名为EncodeFromDirectory的方法 - 这在7zSharp主页上显示。 - Renatas M.
好的,一个简单的问题:为什么你想要使用7zip压缩文件?为什么引用dll是如此糟糕? - Renatas M.
客户的需求是将其压缩为7zip。我想摆脱dll文件,只提供exe文件。 - olidev

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