【问题标题】:Converting TMemoryStream to 'String' in Delphi 2009在 Delphi 2009 中将 TMemoryStream 转换为“字符串”
【发布时间】:2023-04-06 14:08:01
【问题描述】:

在 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;

我们如何转换此代码以使用 Delphi 2009 现在支持 Unicode?​​p>

【问题讨论】:

    标签: delphi string unicode delphi-2009 memorystream


    【解决方案1】:

    您可以将其转换为大小合适的字符指针,然后简单地分配它:

    procedure getMemoryStreamAsString( aMS_ : TMemoryStream );
    var
      ws : widestring; // in newer Delphi it can be string
      ans : ansistring;
    begin
      ws := pwidechar( aMS_.memory );
      // OR
      ans := pansichar( aMS_.memory );
    end;
    

    【讨论】:

      【解决方案2】:

      有一个名为TStringStream 的因素可以为您提供帮助。 . .你可以像这样加载另一个流的内容:

      var StringStream: TStringStream; 
      begin StringStream := TStringStream.Create(''); 
      StringStream.CopyFrom(OtherStream, OtherStream.Size); 
      end;
      

      您现在可以进入这样的字符串类型的系列:数据字符串属性包含系列...但不要尝试使用大型对象,例如在您将大文件加载到某些对象的情况下filestream 然后将其复制到您自己的 stringstream 并努力生成它,因为它会安排大量内存!

      希望有帮助

      【讨论】:

        【解决方案3】:

        我还没有升级,但我的理解是:

        NewCapacity := (M.Size + 1) * SizeOf(Char);
        

        【讨论】:

          【解决方案4】:

          我用:

          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;
          

          仅在 Delphi XE7 上测试过。

          【讨论】:

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

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

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

          这适用于所有 Delphi 版本,而不仅仅是 Delphi 2009。它适用于流为空且没有任何特殊情况的情况。 SetString 是一个被低估的功能。

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

          function MemoryStreamToString(M: TMemoryStream): AnsiString;
          begin
            SetString(Result, PAnsiChar(M.Memory), M.Size);
          end;
          

          这等同于您的原始代码,但会跳过特殊情况。

          【讨论】:

          • 我做过很多Delphi内存的东西,但是我没有听说过SetString,总是用SetLength(dest, length)和一个Move(src, @(dest[1]),长度); SetString 也是如此(它调用 _LStrFromPCharLen)
          • 将其类型转换为 PChar 应该不会产生任何问题。
          • 指针兼容一切。您需要进行类型转换的唯一原因是编译器在重载解析方面遇到问题。
          • 不错的罗伯。我对 SetString 认识不足。
          • 第一个函数不适用于 D7。编译器在第二个参数(“内存”)处失败,并显示消息“不兼容的类型”。所以,它确实需要一个 pchar 类型转换。
          【解决方案6】:

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

          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;
          

          【讨论】:

          • "aStream.Position := 0" 不是必需的,就像您调用“SS.CopyFrom(aStream, 0)”一样,它会将源定位在 0 并为您获取其大小。跨度>
          • 你必须小心 D2009+ 中的 TStringStream,因为它现在是 TEncoding-aware。 CopyFrom() 将按原样复制源 TStream 的原始字节,但 DataString 属性 getter 将使用传递给 TStringStream 构造函数(TEncoding.DefaultTEncoding.UTF8 的任何 TEncoding 来解码这些字节)默认情况下,IIRC)。因此,如果TStream 编码与TStringStream 编码不匹配,则会导致数据丢失/损坏。
          【解决方案7】:

          或者也许您可以重构您的代码以直接使用 TStringStream?您可以使用它代替 TMemoryStream (它们具有相同的接口),您可以通过简单地调用 myString := myStringStream.DataString; 将其“转换”为字符串;

          【讨论】:

          • 确实,这是我首先想到的。为什么不创建一个 TStringStream,在其中加载内存流,然后返回数据字符串?
          猜你喜欢
          • 2010-09-21
          • 2011-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-25
          • 1970-01-01
          相关资源
          最近更新 更多