我正在使用 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
”
有人可以帮助我吗?
检查结果字符串的长度。我认为该字符串包含所有二进制文件,但由于字符串正文中的零,您无法将其视为 ASCII 字符串。 可执行文件的签名(第一个字节):4D 5A 90 00。ASCII 符号:MZP#0(在我的例子中,P 是 ANSI 西里尔字母,符号取决于代码页)。
我使用了:在 Delphi 2009 中将 TMemoryStream 转换为“字符串”以下函数:
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 上运行,用于从互联网上读取 pdf 文件。我花了一个小时才找到这个解决方案。在互联网上找到的所有将内存流转换为字符串的功能都不适合我。这是唯一有效的。 正常的解决方案是:s:=
Http.Get('http://www.test.com/test.exe');
,不使用内存流作为中介。
所有 exe、dll 文件都包含签名 MZP#0 ... 对于 pchar 字符串(delphi 中的大字符串)#0 表示字符串结尾,调试检查器显示 MZP。
如果保留流的原始长度,您可以访问所有数据。
就像其他人建议的那样,在不编码的情况下将二进制 dll 转换为字符串是没有意义的。但如果确实需要,您可以使用: TStringStream 类而不是 TMemoryStream。 和 TStringStream.DataString 属性将获取字符串。 请再次注意,直接将二进制数据转换为字符串可能会导致未指定的结果。使用编码模式:例如:base64、十六进制字符串
使用中间 TStringStream 的方法很慢,因为它将内存从一个地方复制到另一个地方 2 次:
我建议不使用中间对象,直接将内存复制 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);
//(...)
您可以使用 TStringList 类的 LoadFromStream 方法。
仅供记录,在最近的 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;