我开发了通过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?

最佳答案

要在移动应用程序中读取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;

08-18 05:51
查看更多