delphi - 分配给 TStringList 时字符串丢失数据

标签 delphi string unicode delphi-2009 char

我有这个方法,

var
s : TStringList;
fVar : string;
begin
s := TStringList.Create;
fVar := ZCompressStr('text');

ShowMessage( IntToStr(length(fVar) * SizeOf(Char)) );
//24

s.text := fVar;  

ShowMessage( IntToStr( length(s.text) * SizeOf(Char)) );
//18
end;

ZcompressStr 来自 http://www.base2ti.com/zlib.htm 121号线改为 {$ifndef UNICODE} 到 {$ifdef UNICODE} 使其编译。

无论如何,如果我使用 fVar 变量,我可以调用 ZDecompressStr,但是一旦我将它移动到字符串列表或备忘录,它似乎会丢失这 6 个字节的数据......如果我尝试在 s 上使用 ZDecompressStr .text var 由于缓冲区错误而失败。

最佳答案

您没有理由必须更改 ZLibEx.pas 的第 121 行;它对于所有版本的 Delphi 都是正确的,包括 Delphi 2009。 UNICODE符号应该为 Delphi 2009 定义,如果是的话, RawByteString 的类型定义, UnicodeString ,和UnicodeChar应该全部被跳过,因为它们已经是语言中的固有类型。

ZCompressStr将生成一个可能包含不可打印字符(包括空字节)的字符串。它将结果存储在 RawByteString 中,Delphi 特别对待。

TStringList与 Delphi 2009 中的其他所有内容一样,使用 Unicode。它的Text属性的类型为UnicodeString 。当您分配任何UnicodeString时值为 UnicodeString ,您会得到一个转换,如 MultiByteToWideStr API函数。偶RawByteString包含在该规则中。如果您尚未将特定于代码页的字符串值分配给 RawByteString ,那么它将有代码页 0,即 CP_ACP ,系统的默认代码页。

如果字符串实际上并不包含根据系统代码页编码的字符,那么任何转换都会遇到麻烦:垃圾输入,垃圾输出。特别是,无法保证您会获得相同数量的字符。

As Smok1 mentioned , TStringList.Text是一个属性。它有一个 setter 方法,可以将给定的字符串分割成单独的行。当您读取该属性时,它会再次将所有这些行重新连接成一个字符串。设置属性时,TStrings.SetTextStr (在Classes.pas中,如果你好奇的话)将在任何出现 #0 时分割该行, #10 ,或#13 。即空字符、换行符和回车符。当重新连接所有行时,它将使用其 LineBreak属性,使用全局 sLineBreak 进行初始化多变的。最后一个字符串后面也会有一个换行符,因此每行都以 LineBreak 结尾。 。因此,转换不一定是往返的。

因此,有两件事值得我们学习:

  1. 不要将压缩数据视为文本。
  2. 请勿使用TStrings后代来保存您不想处理多个字符串的内容。

另一个好建议:不要使用 string作为通用数据存储类型。仅将其用于实际文本。对于任意二进制数据的存储,首选 TBytes ,或 TMemoryStream 。使用您的示例,您可以像这样压缩字符串:

var
  ss: TStream;
  ms: TMemoryStream;
begin
  ss := TStringStream.Create('text');
  try
    ms := TMemoryStream.Create;
    try
      ShowMessage(IntToStr(ss.Size));
      ZCompressStream(ss, ms);
      ShowMessage(IntToStr(ms.Size));
    finally
      ms.Free;
    end;
  finally
    ss.Free;
  end;
end;

关于delphi - 分配给 TStringList 时字符串丢失数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1351302/

相关文章:

android - 在 Android 上设置线程优先级

c# - Delphi 到 .NET + C#

Java Stream API 比较数组中的字符串

c++ 无法获取 "wcout"来打印 unicode,并让 "cout"继续工作

python - pymysql插入查询中的Unicode值

java - 在 Java 中打印数学符号给出错误的输出

delphi - 我将 $R 指令放在单元中的哪个位置来包含资源有关系吗?

string - Delphi XE2 AnsiFormat() 和 ANSI 字符串常量

C 控制台输入

java - 使用 Java 解析文件并替换双引号内的空格