2015-09-10 81 views
0

在我的应用程序中,我构建了一个xml结构并将其发送给delphi客户端。在该XML我有一个压缩法,Base64编码字符串的标签:解压缩Delphi中的DeflateStream(C#)

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

我的德尔福客户端必须从标签获得的数据,并再次把它变成了即basestring。不幸的是,我得到一个

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.html

Delphi XE and ZLib Problems

http://www.delphipraxis.net/89090-string-mit-gzip-ent-zippen.html

我也试过在C#中解压缩它,不应该吃惊的是它的工作。我想我的问题在于delphi解压缩代码的udnerstanding,或者我可能是一个真正的愚蠢的人。但不幸的是,我没有得到它,我可以如何使这项工作。 :[

TIA

+0

这里有一些不协调的编码。 C#代码将文本编码为UTF-16LE。但是然后你声明一个名为'Utf8Stream'的变量,但是使用'TEncoding.ANSI'。您是否清楚了解正在使用的编码? –

+0

@DavidHeffernan我也尝试过使用其他编码。我没有更改我的测试用例的变量名称。对不起。 – rmbl

回答

3

我要重新编写这两个代码块。我建议你使用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头将不会很重要。

+0

你是一个编码/解码上帝!谢谢! – rmbl

相关问题