-1

我正在使用我在 SO 上的另一篇文章中找到的这些实现。但是有时在读取字符串时,ReadStreamStr 会在字符串中放入额外的字符。因此,我将我的实施发布在这里以对其进行检查和批准,如果有错误,请更正。

function ReadStreamStr(Stream: TStream): string;
{ 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);
  { read characters }
  Stream.Read(Result[1], LenStr);
end;

procedure WriteStreamStr(Stream: TStream; Str: string);
{ writes a string to the stream }
var
  StrLen: Integer;
begin
  { get length of string }
  StrLen := ByteLength(Str);
  { write length of string }
  WriteStreamInt(Stream, StrLen);
  if StrLen > 0 then
    { write characters }
    Stream.Write(Str[1], StrLen);
end;

谢谢你。

4

1 回答 1

4

Integer写在字符前面的是字节,但ReadStreamStr()将其解释为字符数。在 D2007 及更早版本中,stringAnsi 在哪里,效果很好。但在 D2009 及更高版本中,stringUnicode 在哪里,这是行不通的。假设您使用的是 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;
于 2013-05-14T01:57:38.003 回答