在Delphi中解压缩DeflateStream(C#)
在我的应用程序中,我构建了一个xml结构并将其发送到delphi客户端.在该xml的标签中,我有一个压缩的base64编码字符串:
in my application i build a xml structure an send it to a delphi client. In a tag of that xml i have a zipped, base64 coded string:
public static string Zip(string text)
{
byte[] buffer = System.Text.Encoding.Unicode.GetBytes(text);
MemoryStream ms = new MemoryStream();
//using (System.IO.Compression.GZipStream zip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true))
//{
// zip.Write(buffer, 0, buffer.Length);
//}
using (System.IO.Compression.DeflateStream zip = new System.IO.Compression.DeflateStream(ms, System.IO.Compression.CompressionMode.Compress, true))
{
zip.Write(buffer, 0, buffer.Length);
}
ms.Position = 0;
MemoryStream outStream = new MemoryStream();
byte[] compressed = new byte[ms.Length];
ms.Read(compressed, 0, compressed.Length);
byte[] gzBuffer = new byte[compressed.Length + 4];
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
return Convert.ToBase64String(gzBuffer);
}
我的Delphi客户端必须从该标记获取数据,然后再次将其转换为基字符串.不幸的是,我得到了
My Delphi client has to get the data from that tag and turn it into the basestring again. unfortunately, i get a
ezdecompressionerror数据错误
ezdecompressionerror data error
我尝试了互联网提供的一些功能,例如:
I tried some of the functions the internet provides, e.g.:
function ZDecompressString(aText: string): string;
var
Utf8Stream: TStringStream;
Compressed: TMemoryStream;
Base64Stream: TStringStream;
begin
Base64Stream := TStringStream.Create(aText, TEncoding.ASCII);
try
Compressed := TMemoryStream.Create;
try
DecodeStream(Base64Stream, Compressed);
Compressed.Position := 0;
Utf8Stream := TStringStream.Create('', TEncoding.ANSI);
try
ZDecompressStream(Compressed, Utf8Stream);
Result := Utf8Stream.DataString;
finally
Utf8Stream.Free;
end;
finally
Compressed.Free;
end;
finally
Base64Stream.Free;
end;
end;
但是这里没有任何作用.我正在使用XE2和标准的Zlib库.我通读了一些文章,但无法弄清楚:
But nothing worked here. I am using XE2 and the standard Zlib library. I read through some articles but i cant figure something out:
http://forum.codecall.net/topic/76077-zlib-library进行压缩和解压缩/
http://www.yanniel.info/2011/01/string-compress-decompress-delphi-zlib.html
http://www.delphipraxis.net/89090-string-mit-gzip-ent-zippen.html
我也尝试在c#中解压缩它,而不应该怀疑它是否有效.我想我的问题出在delphi减压代码的精通上,或者我是一个真正的愚蠢的人.但不幸的是,我不知道如何进行这项工作.:[
I also tried decompressing it in c# and should not suprise that it worked. I guess my problem lies at the udnerstanding of the delphi decompression code or maybe i am a real dumb person. But unfortunately i dont get it how i can make this work. :[
TIA
我将重新编写两个代码块.我建议您使用UTF-8作为编码.对于大多数西方文字,这是最节省空间的Unicode编码.
I'm going to re-write both blocks of code. I suggest that you use UTF-8 as your encoding. For most western text it is the most space efficient Unicode encoding.
C#代码如下:
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static string Zip(string text)
{
byte[] utf8bytes = System.Text.Encoding.UTF8.GetBytes(text);
MemoryStream compressedStream = new MemoryStream();
using (var gzipStream = new GZipStream(compressedStream,
CompressionMode.Compress, true))
{
gzipStream.Write(utf8bytes, 0, utf8bytes.Length);
}
compressedStream.Position = 0;
byte[] deflated = new byte[compressedStream.Length];
compressedStream.Read(deflated, 0, (int)compressedStream.Length);
return Convert.ToBase64String(deflated);
}
static void Main(string[] args)
{
Console.WriteLine(Zip("fubar"));
Console.ReadLine();
}
}
}
哪个产生以下输出:
H4sIAAAAAAAEAEsrTUosAgDmcA8FBQAAAA==
我基本上保留了与您使用的相同的代码,但是切换到UTF-8并简化了代码,删除了一些不必要的步骤.我还删除了压缩缓冲区长度的写法.我认为没有必要这样做,无论如何它都不尊重网络字节顺序.
I've kept essentially the same code that you used, but switch to UTF-8 and streamlined the code removing some unnecessary steps. I've also removed the writing of the compressed buffer length. I don't see the need for that, and in any case it did not respect network byte order.
更重要的是,我切换到GZIP,因为在Delphi代码中更容易阅读.使用deflate会迫使您进入原始的zlib编程,这有点混乱.使用GZIP将GZIP标头添加到压缩流中.
More importantly I switched to GZIP because it's easier to read that in Delphi code. Using deflate forces you into raw zlib programming which is a bit messy. Using GZIP adds a GZIP header to the compressed stream.
在Delphi端,代码如下:
On the Delphi side the code looks like this:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Classes,
System.ZLib,
Soap.EncdDecd;
function Unzip(const zipped: string): string;
var
DecompressionStream: TDecompressionStream;
Compressed: TBytesStream;
Decompressed: TStringStream;
begin
Compressed := TBytesStream.Create(DecodeBase64(AnsiString(zipped)));
try
// window bits set to 15 + 16 for gzip
DecompressionStream := TDecompressionStream.Create(Compressed, 15 + 16);
try
Decompressed := TStringStream.Create('', TEncoding.UTF8);
try
Decompressed.LoadFromStream(DecompressionStream);
Result := Decompressed.DataString;
finally
Decompressed.Free;
end;
finally
DecompressionStream.Free;
end;
finally
Compressed.Free;
end;
end;
procedure Main;
begin
Writeln(Unzip('H4sIAAAAAAAEAEsrTUosAgDmcA8FBQAAAA=='));
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
当然,对于较小的字符串,压缩开销和GZIP标头表示这不是压缩.加上base64编码后,压缩后+编码的字符串要比输入长得多.
Of course, for small strings the compression overhead and the GZIP header means that this is not compression. Coupled with base64 encoding the compressed + encoded string is much longer than the input.
但是我假设您希望发送大量文本,在这种情况下,GZIP标头将不重要.
I'm presuming however, that you wish to send large amounts of text, in which case the GZIP header will not be significant.