Delphi WideString和Delphi 2009+

时间:2010-11-04 12:34:08

标签: delphi unicode delphi-2010

我正在编写一个将宽字符串保存到二进制文件的类。我正在使用Delphi 2005,但该应用程序稍后将被移植到Delphi 2010.我在这里感到非常不确定,有人可以证实:

  1. Delphi 2005 WideString完全与Delphi 2010相同<{1}}

  2. Delphi 2005 String char以及Delphi 2010 WideString char保证始终大小为2个字节。

  3. 对于所有的Unicode格式,我不希望被我的字符串中的一个字符突然变为3字节宽或类似的东西。

    编辑:发现这个:“我确实说过UnicodeString,而不是WideString.WideString仍然存在,并且没有变化.WideString由Windows内存管理器分配,应该用于交互使用COM对象.WideString直接映射到COM中的BSTR类型。“ at http://www.micro-isv.asia/2008/08/get-ready-for-delphi-2009-and-unicode/

    现在我更加困惑了。那么Delphi 2010 String与Delphi 2005 WideString不一样?我应该使用WideString吗?

    编辑2: Delphi 2005中没有UnicodeString类型.FML。

6 个答案:

答案 0 :(得分:12)

对于您的第一个问题:WideString与D2010的字符串的类型不完全相同。 WideString与其一直以来的COM BSTR类型相同。它由Windows管理,没有引用计数,因此每次将它传递到某处时它都会复制整个BSTR。

UnicodeString,这是D2009中默认的字符串类型,基本上是我们都知道和喜爱的AnsiString的UTF-16版本。它有一个引用计数,由Delphi编译器管理。

对于第二个,默认的char类型现在为WideChar,这些字符与WideString中始终使用的字符相同。它是UTF-16编码,每个字符2个字节。如果将WideString数据保存到文件,则可以毫无困难地将其加载到UnicodeString。这两种类型之间的区别与内存管理有关,而不是数据格式。

答案 1 :(得分:4)

正如其他人提到的,Delphi 2009及更高版本中的字符串(实际上是UnicodeString)数据类型不等同于以前版本中的WideString数据类型,但数据内容格式是相同的。它们都以UTF-16保存字符串。因此,如果您在早期版本的Delphi中使用WideString保存文本,您应该能够在最近版本的Delphi(2009及更高版本)中使用字符串数据类型正确读取它。

您应该注意UnicodeString的性能优于WideString。因此,如果您要在Delphi 2005和Delphi 2010中使用相同的源代码,我建议您在代码中使用带有条件编译的字符串类型别名,这样您就可以充分利用这两个世界:

type
  {$IFDEF Unicode}
  MyStringType = UnicodeString;
  {$ELSE}
  MyStringType = WideString;
  {$ENDIF}

现在,您可以在源代码中使用MyStringType作为字符串类型。如果编译器是Unicode(Delphi 2009及更高版本),那么您的字符串类型将是UnicodeString类型的别名,它在Delphi 2009中引入以保存Unicode字符串。如果编译器不是unicode(例如Delphi 2005),那么您的字符串类型将是旧WideString数据类型的别名。由于它们都是UTF-16,任何版本保存的数据都应该由另一个版本正确读取。

答案 2 :(得分:1)

  1. Delphi 2005 WideString与Delphi 2010 String
  2. 的类型完全相同

    事实并非如此 - ex Delphi 2010字符串隐藏了内部代码页字段 - 但可能对您无关紧要。

    1. 保证Delphi 2005 WideString char以及Delphi 2010 String char的大小始终为2个字节。
    2. 这是事实。在Delphi 2010中,SizeOf(Char)= 2(Char = WideChar)。


      unicode字符串不能有不同的代码页 - 引入代码页字段为Ansi字符串(需要代码页字段)和Unicode字符串(不需要它)创建通用二进制格式。

      如果在Delphi 2005中将WideString数据保存到流中并在Delphi 2010中将相同的数据加载到字符串中,则一切正常。

      WideString = BSTR,并且在Delphi 2005和2010之间没有改变

      UnicodeString = Delphi 2005中的WideString(如果Delphi 2005中存在UnicodeString类型 - 我不知道) Delphi 2009及更高版本中的UnicodeString = string。


      @Marco - Delphi 2009+中的Ansi和Unicode字符串具有通用的二进制格式(12字节标题)。

      UnicodeString代码页CP_UTF16 = 1200;

答案 3 :(得分:0)

规则很简单:

  • 如果您只想在模块中使用unicode字符串 - 请使用UnicodeString类型(*)。
  • 如果您想与COM或其他跨模块目的进行通信,请使用WideString类型。

你看,WideString是一种特殊的类型,因为它不是原生的Delphi类型。它是BSTR的别名/包装器 - 系统字符串类型,用于与COM或跨模块通信一起使用。作为一个unicode - 只是一个副作用。

另一方面,AnsiStringUnicodeString - 是本机Delphi类型,在其他语言中没有模拟。 String只是AnsiStringUnicodeString的别名。

因此,如果您需要将字符串传递给其他代码 - 请使用WideString,否则 - 使用AnsiStringUnicodeString。简单。

P.S。

(*)对于旧的德尔福 - 只是放置

{$IFNDEF Unicode}

type
  UnicodeString = WideString;

{$ENDIF}

代码中的某处。此修复程序将允许您为任何Delphi版本编写相同的代码。

答案 4 :(得分:0)

虽然D2010字符始终是2个字节,但UTF-16字符中存在相同的字符折叠和组合问题,如UTF-8字符。你没有看到这个用窄字符串,因为它们是基于代码页的,但是使用unicode字符串,有可能(在某些情况下常见)有情感但不可见的字符。示例包括unicode文件或流的开头的字节顺序标记(BOM),从左到右/从右到左的指示符字符,以及大量的组合重音。这主要影响“这个字符串在屏幕上会有多少像素宽度”和“此字符串中有多少个字母”的问题(与“此字符串中有多少个字符”不同),但也意味着你可以' t随机地从字符串中删除字符并假设它们是可打印的。像“删除这个单词的最后一个字母”之类的操作变得非常重要,取决于使用的语言。

关于“我的字符串中的一个字符突然变成3个字节长”的问题反映了对UTF如何工作的一点关注。可以(并且有效)在UTF-8字符串中使用三个字节来表示一个可打印字符,但每个字节将是一个有效的UTF-8字符。说,一封信加上两个组合口音。如果使用UTF-16或UTF-32中的三个代码点表示UTF-16或UTF-32长度为3个字节,则不会得到6个字节(或12个字节)长的字符。这使我们正常化(或不)。

但是如果您只处理字符串作为整个事情,那就非常简单 - 您只需将字符串写入文件,然后再读回来。您不必担心细则字符串显示和操作,这些都由操作系统和库处理。 Strings.LoadFromFile(name)和Listbox.Items.Add(string)在D2010中的工作方式与在D2007中完全相同,unicode的东西对程序员来说都是透明的。

答案 5 :(得分:0)

  
    

我正在编写一个将宽字符串保存到二进制文件的类。

  

在D2005中编写课程时,您将使用Widestring 当您迁移到D2010时,Widestring仍然有效且工作正常。 D2005中的Widestring与D2010中的WideString相同。

由于编译器很容易处理这些问题,因此无需考虑D2010中String = WideString的事实。

使用(AString:String)保存的输入例程只需要一行输入proc

procedure SaveAStringToBIN_File(AString:String);
var wkstr : Widestring;
begin
{$IFDEF Unicode}  wkstr := AString;      
{$ELSE}           wkstr := UTF8Decode(AString);   {$ENDIF}
...
   the rest is the same saving a widestring to a file stream
  write the length (word) of string then data 

end;