1

我开发了通过HTTP进行通信的服务器和移动客户端。服务器是用 Delphi 7 编写的(因为它必须与旧代码兼容),客户端是用 XE6 编写的移动应用程序。服务器向客户端发送包含字符串的数据流。一个问题与编码有关。

在服务器上,我尝试以UTF8传递字符串:

//Writes string to stream
procedure TStreamWrap.WriteString(Value: string);
var
  BytesCount: Longint;
  UTF8: string;
begin
  UTF8 := AnsiToUtf8(Value);
  BytesCount := Length(UTF8);

  WriteLongint(BytesCount); //It writes Longint to FStream: TStream

  if BytesCount > 0 then
    FStream.WriteBuffer(UTF8[1], BytesCount);
end;

因为它是用 Delphi7 编写的,所以 Value 是一个单字节字符串。

在客户端上,我以UTF8读取字符串并将其编码为Unicode

//Reads string from current position of stream
function TStreamWrap.ReadString: string;
var
  BytesCount: Longint;
  UTF8: String;
begin
  BytesCount := ReadLongint;
  if BytesCount = 0 then
    Result := ''
  else
  begin
    SetLength(UTF8, BytesCount);

    FStream.Read(Pointer(UTF8)^, BytesCount);

    Result := UTF8ToUnicodeString(UTF8);
  end;
end;

但它不起作用,当我显示带有ShowMessage字母的字符串时是错误的。那么如何在Delphi 7中存储字符串并在移动应用程序上的XE6中恢复呢?我应该在表示字符串的数据的开头添加BOM吗?

4

2 回答 2

4

要在移动应用程序中读取 UTF8 编码的字符串,请使用字节数组和TEncoding类。像这样:

function TStreamWrap.ReadString: string;
var
  ByteCount: Longint;
  Bytes: TBytes;
begin
  ByteCount := ReadLongint;
  if ByteCount = 0 then
  begin
    Result := '';
    exit;
  end;

  SetLength(Bytes, ByteCount);
  FStream.Read(Pointer(Bytes)^, ByteCount);
  Result := TEncoding.UTF8.GetString(Bytes);
end;

这段代码可以满足您在 XE6 中的需要,但是当然,这段代码在 Delphi 7 中无法编译,因为它使用TEncoding. 更重要的是,你的TStreamWrap.WriteString实现在 Delphi 7 中做了你想要的,但在 XE6 中被破坏了。

现在看起来您对 Delphi 7 和 Delphi XE6 版本使用相同的代码库。这意味着您可能需要使用一些条件编译来处理这些版本之间不同的文本。

就我个人而言,我会按照TEncoding. 您需要的是一个将原生 Delphi 转换string为 UTF-8 编码字节数组的函数,以及一个相反方向的相应函数。

所以,让我们考虑字符串到字节函数。我不记得 Delphi 7 是否有TBytes类型。我怀疑不是。所以让我们定义它:

{$IFNDEF UNICODE} // definitely use a better conditional than this in real code
type
  TBytes = array of Byte;
{$ENDIF}

然后我们可以定义我们的函数:

function StringToUTF8Bytes(const s: string): TBytes;
{$IFDEF UNICODE}
begin
  Result := TEncoding.UTF8.GetBytes(s);
end;
{$ELSE}
var
  UTF8: UTF8String;
begin
  UTF8 := AnsiToUtf8(s);
  SetLength(Result, Length(UTF8));
  Move(Pointer(UTF8)^, Pointer(Result)^, Length(Result));
end;
{$ENDIF}

相反方向的功能对您来说应该是微不足道的。

一旦封装了两个 Delphi 版本之间的文本编码处理差异,您就可以在程序的其余部分编写条件自由代码。例如,您将编写WriteString如下代码:

procedure TStreamWrap.WriteString(const Value: string);
var
  UTF8: TBytes;
  ByteCount: Longint;
begin
  UTF8 := StringToUTF8Bytes(Value);
  ByteCount := Length(UTF8);
  WriteLongint(ByteCount);
  if ByteCount > 0 then
    FStream.WriteBuffer(Pointer(UTF8)^, ByteCount);
end;
于 2014-05-12T13:32:06.467 回答
-1

代替

Utf8 : String;

利用

Utf8 : Utf8String;

在客户端。然后转换是自动的。

编辑:由于客户端位于移动平台上,并且 Embarcadero 已决定消除移动编译器中的 8 位字符串,因此上述内容不适用于这种特殊情况。但在您拥有 8 位 UTF-8 编码字符串的其他情况下,Utf8String 可用于在 UTF-8 和 Unicode 字符串之间来回无缝转换,而无需使用显式 UTF-8 转换函数。就像使用它一样

UnicodeStringVariable := Utf8StringVariable;

或者

Utf8StringVariable := UnicodeStringVariable;

并且编译器将插入适当的转换。

于 2014-05-12T12:05:47.680 回答