Delphi XE - RawByteString vs AnsiString

WeG*_*ars 7 delphi delphi-unicode

我在这里遇到了类似的问题:Delphi XE - 我应该使用String还是AnsiString?.在确定在我的(大)库中使用ANSI字符串是正确的之后,我意识到我实际上可以使用RawByteString而不是ANSI.因为我将UNICODE字符串与ANSI字符串混合在一起,所以我的代码现在几乎没有在它们之间进行转换的地方.但是,看起来如果我使用RawByteString我摆脱了那些转换.

请让我知道您对此的看法.
谢谢.


更新:
这似乎令人失望.看起来编译器仍然从RawByteString转换为字符串.

procedure TForm1.FormCreate(Sender: TObject);
var x1, x2: RawByteString;
    s: string;
begin
  x1:= 'a';
  x2:= 'b';
  x1:= x1+ x2;
  s:= x1;              {      <------- Implicit string cast from 'RawByteString' to 'string'     }
end;
Run Code Online (Sandbox Code Playgroud)

我认为它做了一些内部工作(比如复制数据),我的代码也不会快得多,我仍然需要在我的代码中添加大量的类型转换才能使编译器静音.

Arn*_*hez 12

RawByteStringAnsiString默认情况下没有设置代码页的.

将另一个分配string给此RawByteString变量时,您将复制源代码页string.这将包括转换.抱歉.

但还有一个用途RawByteString,即存储普通字节内容(例如数据库BLOB字段内容,就像一个array of byte)

总结一下:

  • RawByteString 应该用作方法或函数的"代码页不可知"参数;
  • RawByteString 可以用作变量类型来存储一些BLOB数据.

如果你想减少转换,并且宁愿string在你的应用程序中使用8位字符,你应该更好:

  • 不要使用泛型AnsiString类型,这将取决于当前的系统代码页,并且您将通过它丢失数据;
  • 依赖于UTF-8编码,即一些8位代码页/字符集,当从或转换为时不会丢失任何数据UnicodeString;
  • 不要让编译器显示有关隐式转换的警告:所有转换都应该是显式的;
  • 使用您自己的专用功能集来处理您的UTF-8内容.

这正是我们为我们的框架所做的.我们想在其内核中使用UTF-8,因为:

  • 我们依靠UTF-8编码的JSON进行数据传输;
  • 内存消耗会更小;
  • 使用过的SQLite3引擎将文本作为UTF-8存储在其数据库文件中;
  • 我们想要一种处理Unicode文本的方法,所有版本的Delphi(从Delphi 6到XE)都没有松散的数据,并且WideString不是一个选项,因为它已经慢了,你也有同样的隐式转换问题.

但是,为了获得最佳速度,我们编写了一些优化函数来处理我们的自定义字符串类型:

  {{ RawUTF8 is an UTF-8 String stored in an AnsiString
    - use this type instead of System.UTF8String, which behavior changed
     between Delphi 2009 compiler and previous versions: our implementation
     is consistent and compatible with all versions of Delphi compiler
    - mimic Delphi 2009 UTF8String, without the charset conversion overhead
    - all conversion to/from AnsiString or RawUnicode must be explicit }
{$ifdef UNICODE} RawUTF8 = type AnsiString(CP_UTF8); // Codepage for an UTF8string
{$else}          RawUTF8 = type AnsiString; {$endif}

/// our fast RawUTF8 version of Trim(), for Unicode only compiler
// - this Trim() is seldom used, but this RawUTF8 specific version is needed
// by Delphi 2009/2010/XE, to avoid two unnecessary conversions into UnicodeString
function Trim(const S: RawUTF8): RawUTF8;

/// our fast RawUTF8 version of Pos(), for Unicode only compiler
// - this Pos() is seldom used, but this RawUTF8 specific version is needed
// by Delphi 2009/2010/XE, to avoid two unnecessary conversions into UnicodeString
function Pos(const substr, str: RawUTF8): Integer; overload; inline;
Run Code Online (Sandbox Code Playgroud)

我们保留了RawByteString处理BLOB数据的类型:

{$ifndef UNICODE}
  /// define RawByteString, as it does exist in Delphi 2009/2010/XE
  // - to be used for byte storage into an AnsiString
  // - use this type if you don't want the Delphi compiler not to do any
  // code page conversions when you assign a typed AnsiString to a RawByteString,
  // i.e. a RawUTF8 or a WinAnsiString
  RawByteString = AnsiString;
  /// pointer to a RawByteString
  PRawByteString = ^RawByteString;
{$endif}

/// create a File from a string content
// - uses RawByteString for byte storage, thatever the codepage is
function FileFromString(const Content: RawByteString; const FileName: TFileName;
  FlushOnDisk: boolean=false): boolean;
Run Code Online (Sandbox Code Playgroud)

源代码可在我们的存储库中找到.在这个单元中,UTF-8相关功能进行了深度优化,两个版本都在pascal和asm中以提高速度.我们有时会重载默认函数(例如Pos)以避免转换,或者可以在此处获得有关我们如何处理框架中文本的更多信息.

遗言:

如果您确定应用程序中只有7位内容(没有突出显示的字符),则可以AnsiString在程序中使用默认类型.但在这种情况下,您最好AnsiStringsuses子句中添加单元以重载字符串函数,以避免大多数不需要的转换.


All*_*uer 11

RawByteString 仍然是一个"AnsiString".最好将其描述为"通用接收器",这意味着它将承担源代码串的代码页在分配点上的任何内容,而不强制进行代码页转换.RawByteString 仅用作函数参数,因此,当您调用使用AnsiStrings的实用程序函数时,您将不会在具有不同代码页关联性的AnsiStrings之间进行转换.

但是,在上面的例子中,您将基本上是AnsiString的内容分配给UnicodeString,这导致转换.它必须进行转换,因为RawByteString具有基于8位字符的有效负载,而字符串(UnicodeString)具有基于16位字符的有效负载.