6

TIdComproessorZLib 组件用于 Delphi/C++ Builder Indy 库中的压缩和解压。CompressStream 方法具有以下定义:

public: virtual __fastcall CompressStream(TStream AInStream, TStream AOutStream, const TIdCompressionLevel ALevel, const int AWindowBits, const int AMemLevel, const int AStrategy);

帮助文件中这些参数的完整描述是:

CompressStream 是一个公共的重写过程。它实现了在祖先类中声明的抽象虚方法。

AInStream 是包含压缩操作中使用的未压缩内容的流。

AOutStream 是用于存储来自压缩操作的压缩内容的流。AOutStream 在从操作中输出压缩内容之前被清除。当省略 AOutStream 时,AInStream 中的流将被清除并重新用于压缩操作的输出。

使用 ALevel 指示操作所需的压缩级别。

使用 AWindowsBits 和 AMemLevel 来控制使用 ZLib 库执行内存压缩所需的内存占用。

使用 AStrategy 来控制压缩操作中使用的 RLE 编码策略。

ALevel 的值在 TIdCompressionLevel 的帮助页面上定义,但我找不到任何指示应该为 AWindowBits、AMemLevel 或 AStrategy 使用哪些值,它们只是整数。

我查看了源代码,但 CompressStream 只是委托给 IndyCompressStream,它在帮助文件中列为:

IndyCompressStream(TStream InStream, TStream OutStream, const int level = Z_DEFAULT_COMPRESSION, const int WinBits = MAX_WBITS, const int MemLevel = MAX_MEM_LEVEL, const int Stratagy = Z_DEFAULT_STRATEGY);

IndyCompressStream 的帮助甚至没有列出 CompressStream 所做的参数的最小描述。

我追踪了(我认为)IndyCompressStream live 中提到的那些默认常量的文件,source\Indy10\Protocols\IdZLibHeaders.pas,它们是

  Z_DEFAULT_STRATEGY    = 0;
  Z_DEFAULT_COMPRESSION  = -1;
  MAX_WBITS = 15; { 32K LZ77 window }
  MAX_MEM_LEVEL = 9;

但是,Z_DEFAULT_COMPRESSION根据文档,给出的值甚至不是该参数的合法值TIdCompressionLevel

是否有一些关于 AWindowBits、AMemLevel 和 AStrategy 对这个组件意味着什么的文档,以及对它们使用哪些值是合理的?上面列出的值是实际推荐的默认值吗?此外,源文件包括“indy”、“Indy10”和“indyimpl”目录。我们应该使用哪些来查找当前 Indy 组件的来源?

谢谢!

4

2 回答 2

4

您需要查看zlib.h中的 zlib 文档。特别是 的参数deflateInit2()

在几乎所有情况下,您唯一应该处理的是压缩级别和窗口位。对于窗口位,您通常会将窗口大小保留为 32K (15),但为 gzip 格式 (31) 添加 16,或取反 (-15) 以获得没有标题或尾部的原始 deflate 格式。对于某些特殊类型的数据,您可能会通过不同的压缩策略获得改进,例如图像或其他数字数据数组。

于 2013-10-04T17:28:12.440 回答
3

感谢您的评论和回答,尤其是 Remy 和 Mark。我没有意识到 Indy 单元是 zlib 的包装器,并且参数是在 zlib 库中定义的。

我试图创建一个 gzip 格式流,用于上传到需要 gzip 的服务器。

这是gzip压缩和解压缩的工作代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
TStringStream* streamIn = new TStringStream(String("This is some data to compress"));
TMemoryStream* streamCompressed = new TMemoryStream;
TStringStream* streamOut = new TStringStream;

/* this also works to compress to gzip format, but you must #include <IdZlib.hpp>
CompressStreamEx(streamIn, streamCompressed, Idzlib::clDefault, zsGZip); */

// NOTE: according to docs, you can leave outstream null, and instream 
// will be replaced and reused, but I could not get that to work

IdCompressorZLib1->CompressStream(                
    streamIn,            // System::Classes::TStream* AInStream,
    streamCompressed,    // System::Classes::TStream* AOutStream,
    1,                   // const Idzlibcompressorbase::TIdCompressionLevel ALevel,
    15 + 16,             // const int AWindowBits, -- add 16 to get gzip format
    8,                   // const int AMemLevel, -- see note below
    0);                  // const int AStrategy);

    streamCompressed->Position = 0;
    IdCompressorZLib1->DecompressGZipStream(streamCompressed, streamOut);

    String out = streamOut->DataString;
    ShowMessage(out);
}

特别要注意,为 ALevel 传递 -1 会产生 ZLib 错误 -2,Z_STREAM_ERROR,这意味着参数无效,尽管我找到了默认值。此外,AWindowBits 通常在 8 到 15 的范围内,但添加 16 会得到 gzip 格式,而负数会得到原始格式,如 zlib 库的作者之一 Mark Adler 引用的 zlib 文档中所述。根据 Mark Adler 的评论,我从 Indy 的默认值更改了 AMemLevel。

此外,如前所述,CompressStreamEx 函数将使用上述注释中包含的参数生成 gzip 压缩。

以上是在 RAD Studio XE3 中测试的。再次感谢你的帮助!

于 2013-10-05T07:31:30.867 回答