2014-02-20 4 views
4

Я в Delphi XE и у меня возникают некоторые проблемы с ZLIB рутин ...Delphi XE и ZLib Проблемы

Я пытаюсь сжать несколько строк (и кодировать его, чтобы отправить его через SOAP WebService -не действительно важно-)

Строка из ZDecompressString отличается в ZCompressString.

example1:

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

example2:

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

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

if '123456789' <> ZDecompressString(ZCompressString('123456789', 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 по умолчанию. И вот первая проблема. Это не полная кодировка Юникода. Как только вы используете символы вне вашей локальной кодовой страницы ANSI, цепочка ломается.

Решите эту проблему, предоставив кодировку при создании экземпляров строкового потока. Передайте кодировку в конструктор TStringStream. Выбор звука - TEncoding.UTF8. Передайте это при создании strInput в компрессоре и strOutput в декомпрессоре.

Теперь следующая и большая проблема, с которой вы сталкиваетесь, заключается в том, что сжатые данные не могут быть значимой строкой в ​​любой кодировке. Вы можете создать свой существующий код, если вы переключитесь на использование AnsiString вместо string. Но это довольно хрупкое решение.

Принципиально вы делаете ошибку, рассматривая двоичные данные как текст. После сжатия у вас есть двоичные данные. Моя рекомендация заключается в том, что вы не пытаетесь интерпретировать сжатый двоичный файл как текст. Оставьте это как двоичное. Сжатие до TBytesStream. И распаковать с TBytesStream. Таким образом, функция компрессора возвращает TBytes, а декомпрессор получает тот же TBytes.

Если по какой-то причине вы должны сжимать строку, тогда вы должны закодировать сжатый двоичный файл. Сделайте это с помощью base64. Блок EncdDecd может сделать это за вас.

Этот поток для компрессора выглядит следующим образом: string -> UTF-8 bytes -> сжатые байты -> base64 string. Очевидно, вы разворачиваете стрелки для распаковки.

+0

Дэвид, Большое спасибо за так хорошо ответ. Вы объясните это очень хорошо. Так хорошо, что новичок, как я, может это понять ...;) – JosepMaria

+0

@Josep Большое спасибо за это. Я это очень ценю. –