在Delphi中解压DeflateStream (c#)
本文关键字:DeflateStream Delphi | 更新日期: 2023-09-27 18:12:10
在我的应用程序中,我构建了一个XML结构并将其发送给Delphi客户端。在该xml的标签中,我有一个压缩的base64编码字符串:
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客户端必须从该标记中获取数据并再次将其转换为基字符串。不幸的是,我得到了一个
ezdecompressionerror数据错误
我尝试了一些互联网提供的功能,例如:
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库。我通读了一些文章,但还是不明白:
http://forum.codecall.net/topic/76077-compress-and-decompress-with-zlib-library/http://www.yanniel.info/2011/01/string-compress-decompress-delphi-zlib.htmlDelphi XE and ZLib Problems
http://www.delphipraxis.net/89090-string-mit-gzip-ent-zippen.html我也试过在c#中解压缩它,应该不会对它的工作感到惊讶。我想我的问题在于对delphi解压缩代码的理解,或者我是一个真正的哑巴。但不幸的是,我不明白我怎么能使这项工作。: [
TIA
我将重新编写这两个代码块。我建议您使用UTF-8作为编码。对于大多数西方文本,它是最节省空间的Unicode编码。
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并简化了代码,删除了一些不必要的步骤。我还删除了压缩缓冲区长度的写入。我不认为有必要这样做,而且无论如何,它都不尊重网络字节顺序。
更重要的是,我切换到GZIP,因为它更容易在Delphi代码中阅读。使用deflate会迫使您使用原始的zlib编程,这有点混乱。使用GZIP会在压缩流中添加一个GZIP头文件。
在Delphi端,代码是这样的:
{$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编码,压缩+编码的字符串比输入长得多。
但是,我假设您希望发送大量文本,在这种情况下,GZIP头将不重要。