我有这个方法,
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
结尾。 。因此,转换不一定是往返的。
因此,有两件事值得我们学习:
- 不要将压缩数据视为文本。
- 请勿使用
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/