【问题标题】:TStream to TStringList fails for unicode Delphi对于 unicode Delphi,TStream 到 TStringList 失败
【发布时间】:2014-10-06 02:22:45
【问题描述】:

如以下代码的Test2所示,TStringList被转换为TStream,然后TStream被转换回TStringList。但是,在 Delphi 7 中,Test2Test1 相同。在 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.

【问题讨论】:

  • 旁白:用DestList := TStringList.Create; try替换DestList := nil; try DestList := TStringList.Create;
  • @DavidHeffernan 你的意思是构造函数中不会有异常吗?当构造函数中可能存在异常时,似乎对 Create 的调用应该驻留在 try-finally 中。你能帮忙评论一下吗? :p
  • 如果构造函数中出现异常,则将调用析构函数,并且不会发生对DestList的赋值。正确的成语是根据我的评论
  • 仔细查看我评论中的代码。如果构造函数引发,那么DestList 确实从未被赋值。而且,这发生在try 之前,所以finally 块没有被执行。仔细查看 RTL/VCL 源代码,看看哪种形式占优势。
  • 是的,就是现场

标签: delphi unicode stream delphi-7 delphi-xe


【解决方案1】:

Test1 将原始String 数据原样写入TMemoryStream,然后将其原样读回String,因此所有版本的Delphi 中的所有内容都正确匹配。 Test2 在 Delphi 2007 及更早版本中工作的原因类似。

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

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

DestList.LoadFromStream(AStream, TEncoding.Unicode);

【讨论】:

  • 非常感谢您的帮助!
猜你喜欢
  • 2015-08-17
  • 1970-01-01
  • 2018-11-28
  • 1970-01-01
  • 2014-09-07
  • 2012-12-05
  • 2021-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多