【问题标题】:Delphi - MemoryStream or FileStreamDelphi - MemoryStream 或 FileStream
【发布时间】:2013-05-04 14:04:55
【问题描述】:

我正在使用 Indy (idHTTP) 从 Internet 下载一个 EXE 文件,我可以使用 memorystream 或 filestream 将其保存到磁盘,但我真的不知道它们之间是否有任何区别(可能在结果结构中文件?)。我还没有找到答案。

这里有两个简单的函数来模拟我在做什么:

Function DownloadMS(FUrl, Dest: String): Boolean;
var
  Http: TIdHTTP;
  Strm: TMemoryStream;
Begin
  Result := False;
  Http := TIdHTTP.Create;
  Strm := TMemoryStream.Create;
  With Http, Strm Do
  Try
    Try
      Get(FUrl, Strm);
      If (Size > 0) Then
      Begin
        Position := 0;
        SaveToFile(Dest);
        Result := True;
      end;
    Except
    end;
  Finally
    Strm.Free;
    Http.Free;
  end;
end;

Function DownloadFS(FUrl, Dest: String): Boolean;
var
  Http: TIdHTTP;
  Strm: TFileStream;
Begin
  Result := False;
  Http := TIdHTTP.Create;
  Strm := TFileStream.Create(Dest, fmCreate);
  With Http, Strm Do
  Try
    Try
      Get(FUrl, Strm);
      Result := (Size > 0);
    Except
    end;
  Finally
    Strm.Free;
    Http.Free;
  end;
end;

您的专家对使用一种或其他类型(内存流或文件流)有何看法?使用一种或其他类型时,EXE 文件的结构有什么不同吗?推荐什么类型?

谢谢!周末愉快!

【问题讨论】:

  • TMemoryStream 在内部使用TFileStream 保存到文件(对于SaveToFile 方法),所以答案很简单——使用TFileStream
  • 我可以考虑使用 TMemoryStream 而不是 TFileStream 的两个原因。避免在发生异常的情况下清理文件系统,并且在将其保存到文件之前需要进行一些操作。
  • 你对with的肆意使用让我害怕。我建议你停止这样做。
  • @bummi,我正在创建一个从我的站点下载应用程序文件的安装程序,我认为您使用 memorystream 是正确的,因为连接可能会失败并产生异常。
  • @bummi,我想说这些方法有缺点,一方面是临时文件混乱,另一方面是内存占用。

标签: delphi filestream indy memorystream idhttp


【解决方案1】:

从流的角度来看,TMemoryStreamTFileStream 没有区别。

它们都是流并保存字节流,并且都派生自TStream

你可以像这样实现你的泛化函数

function DownloadToStream( const AUrl : String; ADest : TStream ): Boolean;
var
  LHttp: TIdHTTP;
begin
  LHttp := TIdHTTP.Create;
  try
    LHttp.Get( AUrl, ADest );
    Result := ADest.Size > 0;
  finally
    LHttp.Free;
  end;
end;

并使用TFileStream 调用它

var
  LStream : TStream;

begin
  LStream := TFileStream.Create( 'MyFile.exe', fmCreate );
  if DownloadToStream( '', LStream ) then
    ...
end;

TMemoryStream 或任何你喜欢的流实例

【讨论】:

  • 确实应该这样重构代码。但我认为问题不在于代码,而在于设计。应该为此目的使用内存流还是文件流似乎是个问题。
  • @DavidHeffernan "我正在从互联网上下载一个 EXE 文件 ...使用一个 EXE 文件 的结构有什么不同吗?还是其他类型?” OP 想知道TMemoryStream 是否会存储与TFileStream 不同的数据:o)
  • 我没有那样读这个问题,我想是因为当你将流存储到磁盘而不是内存时,任何人都可能认为流的内容发生了变化,这似乎很奇怪。这很奇怪!
【解决方案2】:

在许多情况下,在下载和文件之间放置一个中间内存流是没有意义的。所有这一切都会消耗内存,因为您必须先将整个文件放入内存中,然后才能将其放入磁盘。直接使用文件流可以避免这个问题。

文件流选项出现问题的主要情况是,如果您想确保在保存到磁盘之前已成功下载整个文件。例如,如果您要覆盖文件的先前版本,您可能想要下载它,检查哈希签名,然后才覆盖原始文件。在这种情况下,您需要在覆盖之前将文件放在某个临时位置。您可以使用内存流,也可以使用带有临时文件名的文件流。

【讨论】:

  • 是的,我正在创建一个安装程序,也许用户会更新文件。所以我想我会使用 MemoryStream,因为文件不是那么大(2 或 3 MB)。谢谢!
  • @Paruba 如果您愿意,您仍然可以使用文件流。只需使用临时文件名。当您对下载的文件感到满意时,删除旧文件并重命名临时文件。
  • 使用TFileStream 有另一个好处 - 能够恢复中断的下载,而无需从头开始。如果 HTTP 服务器支持字节范围,您可以配置 TIdHTTP 来告诉服务器要发送远程文件的哪个部分,而不是整个文件。对于小文件,这无关紧要,但对于较大的文件,甚至可以使用多个线程一次下载同一文件的不同部分。
猜你喜欢
  • 1970-01-01
  • 2016-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
  • 1970-01-01
  • 2015-12-01
相关资源
最近更新 更多