我开发了一个通过 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 吗?
答案 0 :(得分: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;
答案 1 :(得分:-1)
而不是
Utf8 : String;
使用
Utf8 : Utf8String;
在客户端上。然后转换为自动。
编辑:由于客户端位于移动平台上,而Embarcadero已经决定取消移动编译器中的8位字符串,因此上述情况不会适用于此特定情况。但在其他具有8位UTF-8编码字符串的情况下,Utf8String可用于在UTF-8和Unicode字符串之间无缝转换,而无需使用显式UTF-8转换函数。就像使用一样UnicodeStringVariable := Utf8StringVariable;
或
Utf8StringVariable := UnicodeStringVariable;
并且编译器将插入适当的转换。