Delphi 分配给TStringList时丢失数据的字符串

Delphi 分配给TStringList时丢失数据的字符串,delphi,string,unicode,delphi-2009,char,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

我有这个方法,

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是从,第121行已从更改 {$ifndefunicode} 到 {$ifdef UNICODE} 让它编译


无论如何,如果我使用fVar变量,我可以调用ZDecompressStr,但是一旦我将它移动到stringlist或memo,它似乎会丢失这6个字节的数据。。。。如果我尝试在s.text变量上使用ZDecompressStr,它会失败,并出现缓冲区错误。

这可能是转换-TStringList。text属性是一个属性,而不是变量。您正在以一种有点危险的方式使用它,因为TStringList中有一些文本处理。

您没有理由必须更改ZLibEx.pas的第121行;它适用于所有版本的Delphi,包括Delphi 2009。应仅为Delphi 2009定义
UNICODE
符号,如果是,则应跳过
RawByteString
UnicodeString
UnicodeChar
的类型定义,因为它们已经是语言中的固有类型

ZCompressStr
将生成一个可能包含不可打印字符(包括空字节)的字符串。它将其结果存储在一个
RawByteString
中,Delphi对此进行了专门处理

TStringList
,就像Delphi 2009中的其他东西一样,使用Unicode。其
Text
属性的类型为
UnicodeString
。当您将任何非UnicodeString值指定给UnicodeString时,您将得到一个转换,就像从API函数得到的一样。甚至
RawByteString
也包含在该规则中。如果尚未将特定于代码页的字符串值分配给
RawByteString
,则它将具有代码页0,即
CP\u ACP
,这是系统的默认代码页

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

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

因此,有两件事需要从中学习:

  • 不要将压缩数据视为文本
  • 不要使用
    TStrings
    子体来保存不希望处理多个字符串的内容
  • 另一个好建议是:不要将
    string
    用作通用数据存储类型。仅用于实际文本。对于任意二进制数据的存储,首选
    t字节
    ,或
    t内存流
    。使用您的示例,您可以压缩如下字符串:

    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;
    

    你为什么要用TStringList呢?如果你描述了你想要达到的目标,你就更有可能得到帮助你实现目标的答案。例如,tstringlist可能不是最好的工具(例如,一个字符串数组可能更好),当然,分配给tstringlist.text可能会引起一些混乱(tstringlist.add方法可能是您想要的)。但是,从你的问题很难判断,我之所以使用TStringList是因为我想在压缩数据后将其保存到文件中,为此我通常使用TStringList。这似乎是一个不-不,我一直在摆脱与D2009,但它已经抓住了我。好的一点。事实上,TStringList非常聪明,所以无论是使用DOS风格还是unix风格的终端,这都是一个非常好的答案。你的第一段-是的,这很奇怪,但是你有没有下载并尝试在他们的网站上使用ZlibEx,在我改变这一行之前,它根本不会编译,请看答案的重置是绝对正确的。我一直在使用TStrlingList,因为我想保存文件(TMemoryStream可以这样做),但我想通过互联网上的表单发布这些数据。我会把这一点写下来,修改一下我的问题。谢谢我一直很沮丧。如果能知道我的答案到底出了什么问题,那就太好了?