Delphi XE和ZLib问题

Jos*_*ria 4 compression delphi 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');
Run Code Online (Sandbox Code Playgroud)

例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');
Run Code Online (Sandbox Code Playgroud)

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

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;
Run Code Online (Sandbox Code Playgroud)

哪里错了?

有人有同样的问题吗?

Dav*_*nan 6

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

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

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

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

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

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

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

压缩器的这个流程如下所示:string - > UTF-8 bytes - > compressed bytes - > base64 string.显然你反转箭头来解压缩.