【问题标题】:Appropriate way to cancel saving file via file stream?通过文件流取消保存文件的适当方法?
【发布时间】:2017-10-21 02:20:33
【问题描述】:

我正在编写的一个工具负责在几个小时内下载数千个图像文件。最初,使用TIdHTTP,我会将Get 文件放入TMemoryStream,然后将其保存到文件中,只要没有例外。为了提高速度,我把TMemoryStream改成了TFileStream

但是,现在如果找不到资源,或者任何导致没有实际文件的异常,它仍然会保存一个空文件。

完全可以理解,因为我只是在下载之前创建了一个文件流...

FileStream:= TFileStream.Create(FileName, fmCreate);
try
  Web.Get(AURL, FileStream);
finally
  FileStream.Free;
end;

我知道如果出现异常,我可以简单地删除文件。但这似乎太草率了。我确信有一种更合适的方法可以终止这种情况。

如果出现异常,我应该如何使它不保存文件,同时不改变性能(如果可能的话)?

【问题讨论】:

  • 您可以在TFileStream 上编写自己的包装器,这将延迟创建文件,直到有一些数据要写入它为止。
  • 我将创建自己的文件流类,该类将使用FILE_SHARE_DELETE 共享模式调用CreateFile,当引发Indy 异常时,我将调用DeleteFile 函数(例如,来自该类的方法) 将文件标记为删除,并在文件的最后一个句柄关闭时将其删除(即释放流的时间)。
  • 我将创建一个带有布尔成员的TFileStream 后代,并仅在下载成功时设置该成员,如果未设置布尔值,则让析构函数删除文件。
  • 我知道如果出现异常我可以简单地删除该文件。但这似乎太草率了。 一点也不草率。实际上,这就是异常处理的要点:它是回滚状态的钩子,该状态先前已更改,但由于异常而不再适用。 (人们可能会争论一般异常处理的草率;但这会导致关于无状态和函数式编程的讨论。)

标签: performance delphi indy tfilestream


【解决方案1】:

如果出现异常,我应该如何使它不保存文件,同时不改变性能(如果可能的话)?

这通常是不可能的。任何步骤都可能发生错误和故障,包括下载的部分过程。一旦理解了这一点,那么您必须接受文件可以部分下载然后放弃。你在哪里存储它?

显而易见的选择是内存和文件。您不想存储到内存中,这会留给文件。

这会将您带回到当前的解决方案。

我知道如果出现异常,我可以简单地删除该文件。

这是正确的方法。对此有一些变体。例如,您可以下载到使用标志创建的临时文件,以便在关闭时安排删除。只有下载完成后,您才会复制到真正的目的地。这是浏览器采用的方法。但基本思想是下载到文件,并通过整理来处理任何故障。

【讨论】:

  • 我讨厌 Internet 下载管理器(如 IDM)的一点是,它们有时无法删除 tmp 文件,从而在一个目录中留下一个 5.4 GB 的 tmp 损坏文件(经常发生在我身上)我找不到。
  • @NasreddineAbdelillahGalfout 那是因为它们实施得很差。如果使用FILE_ATTRIBUTE_TEMPORARY,则不会发生这种情况。
  • 谢谢 我不知道这样的标志存在。
【解决方案2】:

如果服务器支持,您可以考虑使用 HTTP 范围请求,而不是一次性下载整个图像。然后您可以将文件分成更小的部分,在第一个完成后请求下一个部分(甚至同时请求多个部分以提高性能)。如果有异常,那么您可以了解未来的请求,因此它们永远不会从一开始就开始。

YouTube 和一些流媒体网站不久前就开始这样做了。过去,如果您开始播放视频,然后暂停它,那么它最终会缓存整个视频。现在它只缓存在当前位置之前一点点。由于视频的放弃率,这可以节省大量带宽。

您可以将部分文件写入磁盘或将其保存在内存中。

【讨论】:

  • 这并没有真正解决所提出的问题。
  • 可能是一个很好的答案,如果它解释了“他们从一开始就没有开始”。但是,该工具确实从任意 URL 下载,因此服务器支持它的保证为零。
猜你喜欢
  • 2012-01-18
  • 2017-10-11
  • 1970-01-01
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
相关资源
最近更新 更多