Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 从旧版本到最新版本的TStringList备份的兼容性_Delphi_Compatibility_Delphi 2007_Unicode String_Tstringlist - Fatal编程技术网

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

Delphi 从旧版本到最新版本的TStringList备份的兼容性,delphi,compatibility,delphi-2007,unicode-string,tstringlist,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,

我有一个使用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备份之前总是“读取”或“写入”(我的意思是在stringlist备份之前和之后都有一些数据)

我是否在这里引入了一个大问题(以防我切换到现代的Delphi版本)? 在未来的delphi版本中,区块是否仍然是可浇铸的(以防我切换?)。我是否需要在备份头中写入字符串版本


不幸的是,我不能测试这个。我想,如果我至少在标题中写入字符串编码类型,我以后就能够以正确的方式对其进行转换,无论是Delphi版本,不是吗?

我认为您的思路是正确的。我记得,几年前,我和你完成了一项类似的任务。我有两个部分用于每个数据块:标题和内容。标头包含诸如块的起始地址和长度之类的信息。内容部分包含实际数据。这种方法从未出现过任何问题。在您的例子中,标题仅包含块的大小。至于string的版本号,我建议您这样做,因为基于Delphi的发布路线,新版本与旧版本不向后兼容是很常见的。即使您以后不必使用版本号,也不会有什么害处。

我认为您的思路是正确的。我记得,几年前,我和你完成了一项类似的任务。我有两个部分用于每个数据块:标题和内容。标头包含诸如块的起始地址和长度之类的信息。内容部分包含实际数据。这种方法从未出现过任何问题。在您的例子中,标题仅包含块的大小。至于string的版本号,我建议您这样做,因为基于Delphi的发布路线,新版本与旧版本不向后兼容是很常见的。即使以后不必使用版本号,也不会有什么害处。

使用
MyStringList.LoadFromStream(Str)
而不是
MyStringList.Text:=PChar(Str.Memory)

首先,您的
TStream
数据不是以null结尾的,但是使用
PChar
这种方式需要一个null终止符(您可以使用带有字符串变量的
SetString()

其次,从D2009开始,
String
现在是
UnicodeString
而不是
AnsiString
PChar
现在是
PWideChar
而不是
PAnsiChar
。您的
TStream
数据是Ansi而不是Unicode(即使在D2009+中,因为
SaveToStream()
默认使用
TEncoding.Default
,即Ansi,用于编码流数据),因此将数据强制转换为
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;
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;
或者这个:

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;
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;

最后,您应该考虑更改流数据以使用UTF-8而不是ANSI,以便将来更好地兼容。D2009+中的

SaveToStream()
LoadFromStream()
都有一个可选的
TEncoding
参数,UTF-8是无损Unicode编码,而Ansi在Ansi/Unicode转换过程中可能丢失数据。如果您现有的数据是ASCII(127以上没有
AnsiChar
字符),那么UTF-8与ASCII是100%向后兼容的。但是,如果数据是Ansi格式(上面有
AnsiChar
字符#127),那么最好以某种方式更改流格式(添加标题/版本等),以便区分旧格式和新格式,然后可以使用Ansi加载旧格式,并使用Unicode/UTF-8保存/加载更新的格式。

使用
MyStringList.LoadFromStream(Str)
而不是
MyStringList.Text:=PChar(Str.Memory)

首先,您的
TStream
数据不是以null结尾的,但是使用
PChar
这种方式需要一个null终止符(您可以使用带有字符串变量的
SetString()

其次,从D2009开始,
String
现在是
UnicodeString
而不是
AnsiString
PChar
现在是
PWideChar
而不是
PAnsiChar
。您的
TStream
数据是Ansi而不是Unicode(即使在D2009+中,因为
SaveToStream()
默认使用
TEncoding.Default
,即Ansi,用于编码流数据),因此将数据强制转换为
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;
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;
或者这个:

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;
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;

最后,您应该考虑更改流数据以使用UTF-8而不是ANSI,以便将来更好地兼容。D2009+中的

SaveToStream()
LoadFromStream()
都有一个可选的
TEncoding
参数,UTF-8是无损Unicode编码,而Ansi在Ansi/Unicode转换过程中可能丢失数据。如果您现有的数据是ASCII(127以上没有
AnsiChar
字符),那么UTF-8与ASCII是100%向后兼容的。但是,如果数据是Ansi(上面有
AnsiChar
字符#127),那么最好以某种方式更改流格式(添加标题/版本等),以便区分较旧的和较新的数据