Integer
写在字符前面的是字节数,但ReadStreamStr()
将其解释为字符数。在 D2007 及更早版本中,string
Ansi 在哪里,效果很好。但在 D2009 及更高版本中,string
Unicode 在哪里,这是行不通的。假设您使用的是 D2009+,这意味着ReadStreamStr()
分配的内存是应有的两倍,但只填充一半,另一半未初始化。您SizeOf(Char)
在阅读时没有考虑(但ByteLength()
在写作时会考虑)。
尝试这个:
function ReadStreamStr(Stream: TStream): string;
{ returns a string from the stream }
var
LenStr: Integer;
LeftOver: array[0..SizeOf(Char)-1] of Byte;
begin
Result := '';
{ get length of string }
LenStr := ReadStreamInt(Stream);
{ set string to get memory }
SetLength(Result, LenStr div SizeOf(Char));
if LenStr > 0 then begin
{ read characters }
Stream.ReadBuffer(Result[1], LenStr);
{ just in case the length was not even }
LenStr := LenStr mod SizeOf(Char);
if LenStr > 0 then
Stream.ReadBuffer(LeftOver[0], LenStr);
end;
end;
或者:
function ReadStreamStr(Stream: TStream): string;
{ returns a string from the stream }
var
LenStr: Integer;
Buf: TBytes;
begin
Result := '';
{ get length of string }
LenStr := ReadStreamInt(Stream);
if LenStr > 0 then begin
{ get memory }
SetLength(Buf, LenStr);
{ read characters }
Stream.ReadBuffer(Buf[1], LenStr);
{ convert to string }
Result := TEncoding.Unicode.GetString(Buf);
end;
end;
无论哪种方式,请记住,如果流数据是在 D2007 或更早版本中写入的,但在 D2009 或更晚版本中读取,则此代码将无法按原样工作。您将不得不采用这种TBytes
方法,但使用更适合TEncoding
解码的方法,例如TEncoding.Default
.
就个人而言,我会选择从一开始就将字符串读/写为 UTF-8:
function ReadStreamStr(Stream: TStream): UTF8String;
{ returns a string from the stream }
var
LenStr: Integer;
begin
Result := '';
{ get length of string }
LenStr := ReadStreamInt(Stream);
{ set string to get memory }
SetLength(Result, LenStr);
if LenStr > 0 then
{ read characters }
Stream.Read(PAnsiChar(Result)^, LenStr);
end;
procedure WriteStreamStr(Stream: TStream; const Str: UTF8tring);
{ writes a string to the stream }
var
StrLen: Integer;
begin
{ get length of string }
StrLen := Length(Str);
{ write length of string }
WriteStreamInt(Stream, StrLen);
if StrLen > 0 then
{ write characters }
Stream.Write(PAnsiChar(Str)^, StrLen);
end;