unicode Delphi的TStream到TStringList失败

unicode Delphi的TStream到TStringList失败,delphi,unicode,stream,delphi-7,delphi-xe,Delphi,Unicode,Stream,Delphi 7,Delphi Xe,如以下代码的Test2所示,TStringList被转换为TStream,然后TStream被转换回TStringList。但是,在Delphi 7中,Test2与Test1给出的代码相同。在unicode Delphi中,Test2不能给出正确的结果。你能帮我提出什么问题吗 program Project1; {$APPTYPE CONSOLE} {$R *.res} uses Classes, SysUtils; // http://stackoverflow.com/questi

如以下代码的
Test2
所示,TStringList被转换为TStream,然后TStream被转换回TStringList。但是,在Delphi 7中,Test2与Test1给出的代码相同。在unicode Delphi中,
Test2
不能给出正确的结果。你能帮我提出什么问题吗

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  Classes, SysUtils;

// http://stackoverflow.com/questions/732666
// Converting TMemoryStream to String in Delphi 2009
function MemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;

procedure Test1;
var
  SrcList: TStrings;
  S: String;
  AStream: TStream;
begin
  SrcList := TStringList.Create;
  try
    with SrcList do
    begin
      Add('aa');
      Add('bb');
      Add('cc');
    end;

    S := SrcList.Text;

    AStream := TMemoryStream.Create;
    try
      // AStream.Write(S[1], Length(S));
      // AStream.Write(S[1], Length(S) * SizeOf(Char));
      AStream.Write(Pointer(S)^, Length(S) * SizeOf(Char));

      WriteLn(MemoryStreamToString(TMemoryStream(AStream)));
    finally
      AStream.Free;
    end;
  finally
    SrcList.Free;
  end;
end;

procedure Test2;
var
  SrcList: TStrings;
  S: String;
  AStream: TStream;
  DestList: TStringList;
  I: Integer;
begin
  SrcList := TStringList.Create;
  try
    with SrcList do
    begin
      Add('aa');
      Add('bb');
      Add('cc');
    end;

    S := SrcList.Text;

    AStream := TMemoryStream.Create;
    try
      // AStream.Write(S[1], Length(S));
      // AStream.Write(S[1], Length(S) * SizeOf(Char));
      AStream.Write(Pointer(S)^, Length(S) * SizeOf(Char));

      DestList := TStringList.Create;
      try
        AStream.Position := 0;
        DestList.LoadFromStream(AStream);

        WriteLn(DestList.Text);
      finally
        DestList.Free;
      end;
    finally
      AStream.Free;
    end;
  finally
    SrcList.Free;
  end;
end;

begin
  try
    Test1;
    Test2;
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Test1
将原始
字符串
数据原样写入
TMemoryStream
,然后原样读回
字符串
,这样所有版本的Delphi中的数据都能正确匹配<代码>测试2在Delphi2007和更早版本中工作,原因类似

Test2
在Delphi 2009及更高版本中失败,因为您没有考虑到
TStrings.LoadFrom…()
(和
TStrings.SaveTo…()
)在这些版本的Delphi中是
TEncoding
-感知的。您正在将UTF-16编码的数据写入
TMemoryStream
,前面没有BOM,然后您就不会告诉
LoadFromStream()
流是UTF-16编码的。它尝试定位BOM表,当找不到BOM表时,它将使用
TEncoding.Default
(又称8bit Ansi)加载流(用于向后兼容旧代码)

因此,在本例中,在Delphi 2009及更高版本中加载流数据时,需要指定流数据的正确编码:

DestList.LoadFromStream(AStream, TEncoding.Unicode);

非常感谢您的帮助性回答!旁白:替换
DestList:=nil;尝试DestList:=TStringList.Create带有
DestList:=TStringList.Create;试试看
@DavidHeffernan你是说构造器中不会有异常吗?当constructore中可能出现异常时,对Create的调用似乎应该驻留在try finally中。你能帮忙评论一下吗如果构造函数中出现异常,则将调用析构函数,并且不会发生对
DestList
的赋值。正确的习惯用法与我的注释一致。请仔细查看注释中的代码。如果构造函数引发,则实际上从未为
DestList
赋值。但是,这也发生在
try
之前,因此不会执行
finally
块。仔细查看一下RTL/VCL源代码,看看哪种格式占主导地位。是的,这是正确的