TStringList备份从旧版本到最新版本的兼容性

时间:2011-11-05 22:59:54

标签: delphi compatibility delphi-2007 unicode-string tstringlist

我有一个使用TStringList的备份系统,但我使用旧的Delphi(Ansi字符串)进行编码。

基本上我保存时会有这个:

...
MyStringList.SaveToStream(Str);
StrSz := Str.Size;
MyBackupStream.Write(StrSz, SizeOf(Integer));
MyBackupStream.Write(Str.Memory^, StrSz);
...

当我重装时:

...
MyBackupStream.Read(StrSz, SizeOf(Integer));
Str.SetSize(StrSz);
MyBackupStream.Read(Str.Memory^, StrSz);
MyStringList.SetText := PChar( Str.Memory);
...

我使用这个顺序(大小+数据大小字节,然后大小+数据大小字节等)系统进行各种组件备份。事实上,在字符串列表备份之前,有些东西总是“读取”或“写入”(我的意思是在StringList备份之前和之后有一些数据)。

我在这里介绍一个大问题(如果我切换到现代Delphi版本)? 在未来的delphi版本中,块是否仍然可以转换(如果我切换?)。我是否有必要在备份标题中编写字符串版本?

不幸的是我无法测试这个。我认为如果我最少在头文件中编写字符串编码类型,我将能够以正确的方式将其转换,无论是Delphi版本,不是吗?

2 个答案:

答案 0 :(得分:2)

使用MyStringList.LoadFromStream(Str)代替MyStringList.Text := PChar( Str.Memory)

首先,您的TStream数据不会以空值终止,但使用PChar的方式需要一个空终止符(您可以使用SetString()和字符串变量来绕过该值)。

其次,从D2009开始,String现在是UnicodeString而不是AnsiStringPChar现在是PWideChar而不是PAnsiChar。您的TStream数据是Ansi而不是Unicode(即使在D2009 +中,因为SaveToStream()默认使用TEncoding.Default(Ansi)来编码流数据),因此将数据转换为{{1将垃圾分配给您的PWideChar

在所有版本中,您应该使用TStringList,但如果您想坚持设置LoadFromStream()属性,那么您需要这样做,它适用于所有版本:

Text

或者这个:

var
  ...
  S: AnsiString;
begin
  ...
  MyBackupStream.ReadBuffer(StrSz, SizeOf(Integer));
  Str.SetSize(StrSz);
  if StrSz > 0 then MyBackupStream.ReadBuffer(Str.Memory^, StrSz);
  SetString(S, PAnsiChar(Str.Memory), StrSz);
  MyStringList.Text := String(S);
  ...
end;

或者这个:

var
  ...
  S: AnsiString;
begin
  ...
  MyBackupStream.ReadBuffer(StrSz, SizeOf(Integer));
  if StrSz > 0 then begin
    SetLength(S, StrSz);
    MyBackupStream.ReadBuffer(S[1], StrSz);
  end;
  MyStringList.Text := String(S);
  ...
end;

最后,您应该考虑将流数据更改为使用UTF-8而不是Ansi,以便将来更好地兼容。 var ... Str: TStringStream; begin ... Str := TStringStream.Create; try MyBackupStream.ReadBuffer(StrSz, SizeOf(Integer)); if StrSz > 0 then Str.CopyFrom(MyBackupStream, StrSz); MyStringList.Text := Str.DataString; finally Str.Free; end; ... end; SaveToStream()在D2009 +中都有一个可选的LoadFromStream()参数,而UTF-8是无损Unicode编码,而Ansi可以在Ansi / Unicode转换期间丢失数据。如果您的现有数据是ASCII(#127以上没有TEncoding个字符),则UTF-8与ASCII完全向后兼容。但是如果数据是Ansi(在#127之上有AnsiChar个字符),那么最好以某种方式更改流格式(添加标题/版本等),这样您就可以区分旧格式和新格式,然后你可以使用Ansi加载旧格式,并使用Unicode / UTF-8保存/加载更新的格式。

答案 1 :(得分:1)

我认为你走在正确的轨道上。我记得,几年前,我完成了与你相似的任务。每个数据块都有两个部分:标题和内容。标头包含诸如起始地址和块长度之类的信息。内容部分包含实际数据。这种方法从来没有任何问题。在您的情况下,标头仅包含块的大小。至于字符串的版本号,我建议你这样做,因为根据Delphi的发布之路,新版本与旧版本不向后兼容是很常见的。即使您以后不必使用版本号,也不会有害。