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

Delphi XE and ZLib Problems

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

我也试过在c#中解压缩它,应该不会对它的工作感到惊讶。我想我的问题在于对delphi解压缩代码的理解,或者我是一个真正的哑巴。但不幸的是,我不明白我怎么能使这项工作。: [

TIA

在Delphi中解压DeflateStream (c#)

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