在Delphi 2009中将TMemoryStream转换为'String'

dmi*_*lam 29 delphi string unicode memorystream delphi-2009

在Delphi 2009之前我们有以下代码:

function MemoryStreamToString(M : TMemoryStream): String;
var
    NewCapacity: Longint;
begin
    if (M.Size = > 0) or (M.Memory = nil) then
       Result:= '' 
    else
    begin
       if TMemoryStreamProtected(M).Capacity = M.Size then
       begin
           NewCapacity:= M.Size+1;
           TMemoryStreamProtected(M).Realloc(NewCapacity);
       end;
       NullString(M.Memory^)[M.Size]:= #0;
       Result:= StrPas(M.Memory);
    end;
end;
Run Code Online (Sandbox Code Playgroud)

我们如何使用Delphi 2009将此代码转换为支持Unicode?

Rob*_*edy 65

您拥有的代码不必要地复杂,即使对于较旧的Delphi版本也是如此.为什么要获取流的字符串版本会强制重新分配流的内存?

function MemoryStreamToString(M: TMemoryStream): string;
begin
  SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char));
end;
Run Code Online (Sandbox Code Playgroud)

这适用于所有Delphi版本,而不仅仅是Delphi 2009.它在流为空时没有任何特殊情况.SetString是一个不被重视的功能.

如果您切换到Delphi 2009时流的内容没有更改为Unicode,那么您应该使用此函数:

function MemoryStreamToString(M: TMemoryStream): AnsiString;
begin
  SetString(Result, PAnsiChar(M.Memory), M.Size);
end;
Run Code Online (Sandbox Code Playgroud)

这相当于您的原始代码,但跳过了特殊情况.

  • 第一个功能不适用于D7.编译器在第二个参数("memory")处失败,并显示消息"不兼容的类型".所以,它确实需要一个pchar类型. (3认同)

Joh*_*mas 16

或者您可以重构代码以直接使用TStringStream?您可以使用它而不是TMemoryStream(它们具有相同的接口),您只需调用myString:= myStringStream.DataString即可将其"转换"为字符串.


Nic*_*ges 13

一种"更清洁"的方式可能是:

function StreamToString(aStream: TStream): string;
var
  SS: TStringStream;
begin
  if aStream <> nil then
  begin
    SS := TStringStream.Create('');
    try
      SS.CopyFrom(aStream, 0);  // No need to position at 0 nor provide size
      Result := SS.DataString;
    finally
      SS.Free;
    end;
  end else
  begin
    Result := '';
  end;
end;
Run Code Online (Sandbox Code Playgroud)

  • 在D2009 +中你必须要小心`TStringStream`,因为现在它是'TEncoding`.`的copyfrom()`将复制源`TStream`原样的原始字节,但`DataString`属性getter将使用任何`TEncoding`被传递给`TStringStream`构造(`TEncoding.Default`解码这些字节或者`TEncoding.UTF8`默认情况下,IIRC).因此,如果`TStream`编码与`TStringStream`编码不匹配,您将获得数据丢失/损坏. (8认同)

Ive*_*aev 6

我用:

function StreamToString(const Stream: TStream; const Encoding: TEncoding): string;
var
  StringBytes: TBytes;
begin
  Stream.Position := 0;
  SetLength(StringBytes, Stream.Size);
  Stream.ReadBuffer(StringBytes, Stream.Size);
  Result := Encoding.GetString(StringBytes);
end;
Run Code Online (Sandbox Code Playgroud)

它仅在 Delphi XE7 上进行了测试。

  • `TBytes` 是一个动态数组。`ReadBuffer()` 的第一个参数是一个无类型的 `var` 您需要取消引用 `TBytes` 以获得正确的内存地址以传递给 `ReadBuffer()`,例如: `ReadBuffer(StringBytes[0], .. .)` 或更安全的 `ReadBuffer(PByte(StringBytes)^, ...)` 当 `Size` 为 0 时。 (3认同)