写入TMemoryStream并丢失unicode

时间:2012-07-27 15:20:19

标签: delphi delphi-xe2

使用Delphi XE2将TMemoryStream(包含unicode字符串)复制到另一个TMemoryStream时,我发现了一个奇怪的行为:

我有两个TMemoryStream实例。第一个实例包含unicode文本(SourceMS)。我将一些任意数据写入第二个MemoryStream(DestMS),然后将第一个流的内容复制到第二个流中,如下所示:

var
  SomeInt: Integer;
  SomeByte: Byte;
  SourceMS, DestMS: TMemoryStream;
begin
  ...
  DestMS.Write(SomeInt, SizeOf(SomeInt));
  DestMS.Write(SomeByte, SizeOf(SomeByte));
  SourceMS.SaveToFile('c:\SourceMS.txt');  // SourceMS.txt contains the unicode chars
  DestMS.CopyFrom(SourceMS, 0);          // copy the whole content of SourceMS to DestMS   
  DestMS.SaveToFile('c:\DestMS.txt');  // DestMS.txt DOEST NOT contain unicode chars              
end;

如何在不丢失unicode(具有隐式转换)的情况下将第一个流的内容复制到第二个流? 当我说“丢失unicode”时,我的意思是:unicode字符串确实被复制到第二个流,但是unicode丢失了。我只获得ANSI字符。

3 个答案:

答案 0 :(得分:1)

似乎DestMS只是一些任意字节,SourceMS是你的Unicode内容所在的位置。如果您将source追加到dest,那么来自BOM的{​​{1}}将不会位于内存流的开头。当您在Windows中打开保存的文本文件时,它将看不到source,因为它不在文件的开头,所以它不会知道文件后面的其他字符应该被视为的Unicode。

您似乎正在尝试在Unicode内容的前面插入一些内容。

如果是这样,那么您可以将Unicode内容放在符合Unicode的控件中,将字符添加到开头,然后从控件中捕获内容。这会使BOM保持在字节流的开头。

答案 1 :(得分:1)

如果我们仅根据发布的5行代码来判断这一点,那么可能会发生什么。 TMemoryStream不会以任何方式改变字节,我们必须假设原始字节已成功从一个.txt文件复制到另一个{{1}}文件。这两个文件应包含完全相同的字节,但在使用Text Viewer应用程序查看文件时,这些相同的字节不会以相同的方式解释。

我只能想象一个这样的案例:

  • 其中一个文件有BOM,很可能是UTF8。
  • 另一个文件没有BOM,因此它被解释为ANSI。

哪个文件有BOM表无关紧要:通过这样的过程会改变字节的解释方式。根据维基百科的说法,绝大多数代码页都是超集的ASCII,这意味着所有可以使用7位写入的字节都可以用UTF8和ANSI完全相同的方式进行解释。 OP抱怨的“Unicode”字符肯定在“扩展”ANSI(8位)中,或者,当使用UTF8时,它们使用2个或更多字节组成。这给出了失败模式:

  • 如果原始文件是包含扩展字符(非ASCII)的ANSI文件,如果它们被解释为UTF8,结果可能看起来有点像垃圾:原始文件的两个(或更多)字符似乎被一些奇怪的角色取代。
  • 如果原始版本是UTF8,那么所有国际字符都将使用至少两个字节来表示:当解释为ANSI时,根据PC的代码页,这两个字节将表示为两个不同的字符。

答案 2 :(得分:0)

CopyFrom确实将整个源流复制到目标流中,但它从目标的当前位置开始。之前写的任意数据仍然存在!

在致电MS1.Position := 0之前,您应该设置CopyFrom