通过文件流取消保存文件的适当方法?

问题描述:

我正在写的一个工具负责在数小时内下载数千个图像文件。最初,使用TIdHTTP,我将Get文件转换为TMemoryStream,然后将其保存到文件中,只要没有例外。为了提高速度,我将TMemoryStream更改为TFileStream通过文件流取消保存文件的适当方法?

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

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

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

我知道我可以简单删除该文件,如果有异常。但它似乎太sl。。我相信有一种更恰当的方法来中止这种情况。

如何在不改变性能(如果可能的话)的情况下保存文件的情况下保存文件?

+1

你可以在'TFileStream'上编写你自己的包装,它会延迟创建一个文件,直到有一些数据写入它为止。 – EugeneK

+2

我会创建我自己的文件流类,它将调用具有FILE_SHARE_DELETE共享模式的'CreateFile',并且当发生Indy异常时,我会调用标记文件以进行删除的'DeleteFile'函数(例如,从该类的方法)并在关闭文件的最后一个句柄时(即释放流时)将其删除。 – Victoria

+1

我将创建一个带有布尔成员的'TFileStream'后代,并且只有在下载成功时才设置该成员,然后在未设置布尔值的情况下让析构函数删除文件。 –

我应该如何使这不保存文件,如果有异常,而不改变性能(如果可能的话)?

这是不可能的。错误和失败可能发生在任何一步,包括部分路径下载。一旦理解了这一点,那么您必须接受该文件可以被部分下载然后放弃。你在哪里存储它?

显而易见的选择是内存和文件。你不想存储到内存中,然后保存到文件中。

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

我知道我可以简单地删除文件,如果有例外。

这是正确的方法。这有几个变种。例如,您可以下载到使用标志创建的临时文件,以在关闭时排列其删除。只有在下载完成后才能复制到真正的目的地。这是浏览器所采用的方法。但基本思想是下载归档并通过整理来处理任何故障。

+0

有一件事我讨厌Internet下载管理器(比如IDM),他们有时候无法删除tmp文件而离开你5.4 GB tmp损坏的文件(在我身上发生很多)在我无法找到的目录中。 –

+0

@NasreddineAbdelillahGalfout这是因为他们执行不力。如果使用了'FILE_ATTRIBUTE_TEMPORARY',那就不可能发生。 –

+0

谢谢我不知道这样的标志存在。 –

而不是一次下载整个图像,你可以考虑使用HTTP范围请求,如果服务器支持它。然后,您可以将文件分块成较小的部分,在第一部分完成后请求下一部分(或者甚至同时请求多个部分以提高性能)。如果有例外,那么你可以关于未来的要求,所以他们从不首先开始。

YouTube和许多流媒体网站刚刚开始这样做。它曾经是如果你开始播放视频,然后暂停它,那么它最终会缓存整个视频。现在它只在当前位置前缓存一点。由于视频的放弃率,这节省了大量的带宽。

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

+1

这并没有真正解决被问到的问题。 –

+0

如果它解释了“*他们永远不会从第一个地方开始*”,这个*可能*是一个很好的答案。但是,该工具确实从任意URL下载,因此服务器不支持它。 –