-1

我正在使用 IdHttp 从网上下载一个文件,如下所示:

var
 MS: TMemoryStream;

procedure Test1;
var
 Http: TIdHTTP;
begin
Http := TIdHTTP.Create(nil);
  try
    MS := TMemoryStream.Create;
    try
      Http.Get('http://www.test.com/test.exe', MS);
    finally
      MS.Free;
    end;
  finally
    Http.Free;
  end;
end;

因此,下载的文件/流(不知道如何发音)将在MS.Memory.

好吧,我想获取或转换MS.Memory为字符串,反之亦然。

我已经尝试过 Rob Kennedy 在这个问题中发布的函数:Converting TMemoryStream to 'String' in Delphi 2009

但我刚刚得到了字符串:“ MZP

谁能帮我?

4

7 回答 7

4

检查结果字符串的长度。我想该字符串包含所有二进制文件,但由于字符串正文中的零,您无法将其视为 ASCII 字符串。可执行文件的签名(第一个字节):4D 5A 90 00。ASCII 符号:MZP#0(在我的例子中,P 是 ANSI Cyrillic,符号取决于代码页)。

于 2012-05-05T14:37:46.300 回答
2

我使用过:Converting TMemoryStream to 'String' in Delphi 2009以下函数:

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;

之后Http.Get('http://www.test.com/test.exe', MS);就可以使用了:s:=StreamToString(MS);

s 是字符串。对我来说,它在 Delphi 10.2 上工作,用于从 Internet 读取 pdf 文件。我花了一个小时才找到这个解决方案。在互联网上找到的将内存流转换为字符串的所有功能都不适合我。这是唯一有效的。正常的解决方案是:s:=Http.Get('http://www.test.com/test.exe'); 不使用内存流作为中介。

于 2019-08-04T15:53:01.950 回答
1

就像其他人建议的那样,将二进制 dll 转换为不编码的字符串是没有意义的。但如果确实需要,您可以使用:TStringStream 类而不是 TMemoryStream。并且 TStringStream.DataString 属性将获取字符串。请再次注意,直接将二进制数据转换为字符串可能会导致未指定的reuslt。使用编码模式:例如:base64,十六进制字符串

于 2012-11-04T09:37:30.423 回答
1

所有 exe、dll 文件都包含一个签名 MZP#0 ... 对于 pchar 字符串(delphi 中的巨大字符串),#0 表示字符串的结尾,并且您的调试检查器显示 MZP。

如果您保留流的原始长度,则可以访问所有数据。

于 2012-05-06T06:36:33.053 回答
0

您可以使用 TStringList 类的 LoadFromStream 方法。

于 2012-05-05T17:54:41.513 回答
0

仅作记录,在最近的 Delphi 中,您可以使用 TStreamReader/TStreamWriter 从/向 TStream 后代读取/写入字符串,如下面的代码所示(其中 LoadFromString/SaveToString 是您自己的方法来处理您的字符串从流中读取并分别从您的某个对象中获取字符串,以便将其写入流中):

procedure TStoryItem.LoadReadCom(const Stream: TStream);

begin
  var reader := TStreamReader.Create(Stream);
  LoadFromString(reader.ReadToEnd);
  FreeAndNil(reader); //the reader doesn't own the stream by default, so this won't close the stream
end;

procedure TStoryItem.SaveReadCom(const Stream: TStream);
begin
  var writer := TStreamWriter.Create(Stream);
  writer.Write(SaveToString);
  FreeAndNil(writer); //the writer doesn't own the stream by default, so this won't close the stream
end;
于 2021-12-08T23:24:45.487 回答
0

使用中间 TStrinStream 的方法很慢,因为它将内存从一个地方复制到另一个地方 2 次:

  1. 在调用 TStringStream.CopyFrom 方法时,
  2. 并在最终分配 Result := TStringStream.DataString

我建议不使用中间对象,直接将内存复制 1 次到结果中。这是我的功能:



    Function TryMemoryStreamToString(const MS: TMemoryStream; var s: string): Boolean;
      begin
        Result := False; if(MS=nil)then exit;
        try
          SetLength(s, MS.Size - MS.Position);
          MS.Read(s[1], Length(s));
          Result := True;
        except
          Result := False;
        end;
      end;

当然,您也可以直接将字符串作为结果返回:



    Function MemoryStreamToStringDef(const MS: TMemoryStream; const ADefault: string = ''): string;
      begin
        if Assigned(MS)
           then try
                  SetLength(Result, MS.Size - MS.Position);
                  MS.Read(Result[1], Length(Result));
                except
                  Result := ADefault;
                end
           else Result := ADefault;
      end;

请记住,从 MemoryStream 读取将从 TMemoryStream.Position 指向的任何位置开始。因此请注意这一点,并确保它位于您想要的位置,例如,如果您始终想要整个内容,在调用函数之前将其设置为流的开头:



    var
      MS : TMemorySTream;
      s  : string;

    //(...)
      MS.Position := 0; 
      s := MemoryStreamToStringDef(MS);
    //(...)

于 2020-05-07T04:28:06.993 回答