TIdHTTP 文件流下载不完整

TIdHTTP filestream incomplete downloads

我正在使用 TIdHTTP.Get() 将(可能很大的)文件检索到 TFileStream,基本上;

filestream := TFileStream.Create(destination, fmCreate);
http.HandleRedirects := True;
try
  http.Get(url, filestream);
except
  on E: Exception do Memo.Lines.Add(E.Message);
end;
filestream.Free;

我的问题是 when/if 用户 closes/kills 下载过程中的程序。文件大小不是显示为小于应有的大小,而是已完成下载的大小。这是为什么?

我使用文件大小来快速检查下载是否成功,因此大小合适,但错误的内容会导致其他错误。我不想对每个文件进行哈希校验和,因为它们有很多,而且 MD5 检查需要一段时间才能处理更大的多 GB 大小的文件。

如果下载因任何原因中断,是否有办法减小目标文件的大小?除非所有下载都已完成,否则不将流扩展到完整大小的一些方法好吗?

如果文件大小在下载开始时已知,即在 HTTP Content-Length header 中,则 TIdHTTP(更具体地说,TIdIOHandler.ReadStream())pre-allocates 流到完整大小以提高 I/O 下载期间的性能。

如果下载(不是应用程序)过早终止,ReadStream() 有逻辑来减少流的大小以匹配实际下载的字节数。因此,在这种情况下,除非下载完成,否则不应保留完整大小的文件。

但是,如果用户终止应用程序,则该代码不会 运行,所以是的,文件将保留 pre-allocated 大小。目前 Indy 中没有选项可以禁用 pre-allocate 逻辑。实际上,代码中有一个 TODO 项目。

同时,有一个简单的解决方法 - 您可以从 TFileStream 派生自定义 class 并覆盖其虚拟 SetSize() 方法(Size 属性's setter) 什么也不做。 Indy 不验证实际应用了请求的大小。只要流的 SizePosition 属性 getter 正常工作,你应该没问题。

type
  TFileStreamNoPreSize = class(TFileStream)
  protected
    procedure SetSize(const NewSize: Int64); override;
  end;
    
procedure TFileStreamNoPreSize.SetSize(const NewSize: Int64);
begin
  // do nothing...
end;

...

filestream := TFileStreamNoPreSize.Create(destination, fmCreate);