我有一个使用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版本,不是吗?
答案 0 :(得分:2)
使用MyStringList.LoadFromStream(Str)
代替MyStringList.Text := PChar( Str.Memory)
。
首先,您的TStream
数据不会以空值终止,但使用PChar
的方式需要一个空终止符(您可以使用SetString()
和字符串变量来绕过该值)。
其次,从D2009开始,String
现在是UnicodeString
而不是AnsiString
而PChar
现在是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的发布之路,新版本与旧版本不向后兼容是很常见的。即使您以后不必使用版本号,也不会有害。