Delphi XE和ZLib问题

时间:2014-02-20 14:33:02

标签: delphi compression zlib

我在Delphi XE中,我在使用ZLib例程时遇到了一些问题......

我正在尝试压缩一些字符串(并对其进行编码以通过SOAP Web服务发送 - 这并不重要 - )

ZDecompressString的字符串结果与ZCompressString中使用的不同。

例1:

uses ZLib;
// compressing string
// ZCompressString('1234567890', zcMax); 
// compressed string ='xÚ3426153·°4'

// Uncompressing the result of ZCompressString, don't return the same:
// ZDecompressString('xÚ3426153·°4'); 
// uncompressed string = '123456789'

if '1234567890' <> ZDecompressString(ZCompressString('1234567890', zcMax)) then
  ShowMessage('Compression/Decompression fails');

例2:

Uses ZLib;
// compressing string
// ZCompressString('12345678901234567890', zcMax) 
// compressed string ='xÚ3426153·°40„³'

// Uncompressing the result of ZCompressString, don't return the same:
// ZDecompressString('xÚ3426153·°40„³') 
// uncompressed string = '12345678901'

if '12345678901234567890' <> ZDecompressString(ZCompressString('12345678901234567890', zcMax)) then
  ShowMessage('Compression/Decompression fails');

使用的函数来自其他一些关于压缩和解压缩的帖子

function TForm1.ZCompressString(aText: string; aCompressionLevel: TZCompressionLevel): string;
var
  strInput,
  strOutput: TStringStream;
  Zipper: TZCompressionStream;
begin
  Result:= '';
  strInput:= TStringStream.Create(aText);
  strOutput:= TStringStream.Create;
  try
    Zipper:= TZCompressionStream.Create(strOutput, aCompressionLevel);
    try
      Zipper.CopyFrom(strInput, strInput.Size);
    finally
      Zipper.Free;
    end;
    Result:= strOutput.DataString;
  finally
    strInput.Free;
    strOutput.Free;
  end;
end;

function TForm1.ZDecompressString(aText: string): string;
var
  strInput,
  strOutput: TStringStream;
  Unzipper: TZDecompressionStream;
begin
  Result:= '';
  strInput:= TStringStream.Create(aText);
  strOutput:= TStringStream.Create;
  try
    Unzipper:= TZDecompressionStream.Create(strInput);
    try
      strOutput.CopyFrom(Unzipper, Unzipper.Size);
    finally
      Unzipper.Free;
    end;
    Result:= strOutput.DataString;
  finally
    strInput.Free;
    strOutput.Free;
  end;
end;

我哪里错了?

其他人有同样的问题吗?

1 个答案:

答案 0 :(得分:6)

与我所知的所有压缩代码一样,ZLib是一种二进制压缩算法。它对字符串编码一无所知。您需要为其提供压缩的字节流。当你解压缩时,你会得到回字节流。

但是你正在使用字符串,因此需要在编码文本和字节流之间进行转换。 TStringStream类正在您的代码中执行该操作。在创建字符串流实例时,可以为其提供文本编码。

只有您的代码不提供编码。因此使用默认的本地ANSI编码。这是第一个问题。这不是完整的Unicode编码。只要您使用本地ANSI代码页之外的字符,链就会崩溃。

通过在创建字符串流实例时提供编码来解决该问题。将编码传递给TStringStream构造函数。一个合理的选择是TEncoding.UTF8。在压缩器中创建strInput并在解压缩器中创建strOutput时传递此信息。

现在,您遇到的下一个更大问题是您的压缩数据在任何编码中都可能不是有意义的字符串。如果您切换到使用AnsiString而不是string,则可以使现有代码有效。但这是一个相当脆弱的解决方案。

从根本上说,你犯了将二进制数据视为文本的错误。压缩后,您就拥有了二进制数据。我的建议是您不要尝试将压缩二进制文件解释为文本。把它留作二进制。压缩到TBytesStream。并从TBytesStream解压缩。因此压缩器函数返回TBytes,解压缩器接收到相同的TBytes

如果由于某种原因必须压缩为字符串,则必须对压缩的二进制文件进行编码。使用base64做到这一点。 EncdDecd单元可以为您完成。

压缩器的这个流程如下所示:string - &gt; UTF-8字节 - &gt;压缩字节 - &gt; base64字符串。显然你反转箭头来解压缩。