【问题标题】:Decompression Stream in Delphi 7 and Delphi XE4Delphi 7 和 Delphi XE4 中的解压流
【发布时间】:2013-12-11 07:19:52
【问题描述】:

以下是我的函数,它接受压缩文件并通过一次读取 1024 个字符将其转换为 txt 文件。

procedure DecompressFile(const ACompressedFile, ADestinationFile : String);
var
  SourceStream : TFileStream;
  DestinationStream : TFileStream;
  DecompressionStream : TDecompressionStream;

  nRead : Integer;
  Buffer: array [0..1023] of Char;
begin
  SourceStream := TFileStream.Create(ACompressedFile, fmOpenRead);
  try
    DestinationStream := TFileStream.Create(ADestinationFile, fmCreate);
    try
      DecompressionStream := TDecompressionStream.Create(SourceStream);
      try
        repeat
          nRead := DecompressionStream.Read(Buffer, 1024);
          DestinationStream.Write(Buffer, nRead);
        until nRead = 0;
      finally
        DecompressionStream.Free;
      end;
    finally
      DestinationStream.Free;
    end;
  finally
    SourceStream.Free;
  end;
end;

我的问题是这会在 Delphi 7 的情况下生成正确的 txt 文件,但在 Delphi XE4 的情况下,它会在每个字符之间引入垃圾值。

例子:

Delphi 7: abcdedfgh
Delphi XE4: aNULbNULcNULdNULeNULfNULgNULhNUL

NUL 被插入到每个字符之间。我尝试更改声明

Buffer: array [0..1023] of Char;

Buffer: array [0..1023] of AnsiChar;,但这不起作用。

【问题讨论】:

  • 缓冲区最好使用Byte数组而不是Char,但这里没有问题。对于 XE4 文本看起来像 unicode 编码(UTF16?),对于拉丁符号,它总是对 - 0 + ascii 代码。你确定你在输入上有相同的 TXT 文件(也许你从代码创建测试文件)并且输出没有任何其他转换(比如将数据读入字符串或其他东西)?
  • 在我看来,您好像直接从您移植的巨大应用程序中发布了代码。但是,如果您发布了 SSCCE,那就容易多了。如果你这样做了,你肯定会自己解决问题。你读过 Marco 的论文了吗?
  • @DavidHeffernan - 我正在并排阅读。
  • Delphi XE4 默认使用 Unicode 字符串。您的输出文本文件可能根本不是垃圾,您只需将它们作为 Utf-16 编码的文本文件打开。

标签: delphi delphi-7 delphi-xe4


【解决方案1】:

首先让我们假设解压流类,不管它是什么,都被正确实现了。在这种情况下,问题中的代码实际上很好。它成功解压缩文件。虽然,它有点草率,因为它分配的缓冲区是您使用的两倍大。缓冲区应该是字节数组而不是字符数组。使用 SizeOf(Buffer) 而不是重复那个神奇的 1024 常量。而Write调用最好是WriteBuffer来添加错误检查。

这两种输出的区别只是一个用8位编码编码,另一个用16位编码编码,可能是UTF-16。

这是否是故意的很难说。需要查看创建压缩文件的过程。例如,也许压缩文件是通过压缩 Delphi 字符串创建的。在 D7 中该字符串是 8 位编码的,但在 DXE4 中是 16 位编码的。

一个明显的步骤是比较两个输入文件,D7 与 DXE4 文件。您希望它们是相同的。但他们是吗?


那么另一个可能的原因是你的解压流类被破坏了。它看起来像已知的好ZLib类。

【讨论】:

  • 你是对的。我的被​​压缩的 XML 文件是错误的。 FCompressionStream.Write(strBuffer[1], Length(strBuffer)) 一次接受一行并压缩它。但是我观察到了 Lenght(strBuffer) 的问题,因为它将字符串减半,因为我认为 unicode delphi 中的字符大小是两倍。所以,我将它乘以 2 来解决问题。我最终的delphi代码是: FCompressionStream.Write(strBuffer[1], Length(strBuffer) * 2)
  • 代码应该是FCompressionStream.Write(Pointer(strBuffer)^, Length(strBuffer) * SizeOf(Char))
【解决方案2】:

这个修正应该可以解决 D7 和 DXE4 之间的差异:

Buffer: array [0..1023] of **Ansi**Char;

但在操作内存时,最好避免使用可能造成编码不利影响的字符...最好使用字节

Buffer: array [0..1023] of **Byte**;

然后,如果没有缓冲区,那就更好了:

DestinationStream.CopyFrom(DecompressionStream , DecompressionStream.Size);

【讨论】:

    猜你喜欢
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 2013-11-04
    • 2013-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多