2017-10-21 78 views
4

我正在寫的一個工具負責在數小時內下載數千個圖像文件。最初,使用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'後代,並且只有在下載成功時才設置該成員,然後在未設置布爾值的情況下讓析構函數刪除文件。 –

回答

11

我應該如何使這不保存文件,如果有異常,而不改變性能(如果可能的話)?

這是不可能的。錯誤和失敗可能發生在任何一步,包括部分路徑下載。一旦理解了這一點,那麼您必須接受該文件可以被部分下載然後放棄。你在哪裏存儲它?

顯而易見的選擇是內存和文件。你不想存儲到內存中,然後保存到文件中。

這會將您帶回當前的解決方案。

我知道我可以簡單地刪除文件,如果有例外。

這是正確的方法。這有幾個變種。例如,您可以下載到使用標誌創建的臨時文件,以在關閉時排列其刪除。只有在下載完成後才能複製到真正的目的地。這是瀏覽器所採用的方法。但基本思想是下載歸檔並通過整理來處理任何故障。

+0

有一件事我討厭Internet下載管理器(比如IDM),他們有時候無法刪除tmp文件而離開你5.4 GB tmp損壞的文件(在我身上發生很多)在我無法找到的目錄中。 –

+0

@NasreddineAbdelillahGalfout這是因爲他們執行不力。如果使用了'FILE_ATTRIBUTE_TEMPORARY',那就不可能發生。 –

+0

謝謝我不知道這樣的標誌存在。 –

0

而不是一次下載整個圖像,你可以考慮使用HTTP範圍請求,如果服務器支持它。然後,您可以將文件分塊成較小的部分,在第一部分完成後請求下一部分(或者甚至同時請求多個部分以提高性能)。如果有例外,那麼你可以關於未來的要求,所以他們從不首先開始。

YouTube和許多流媒體網站剛剛開始這樣做。它曾經是如果你開始播放視頻,然後暫停它,那麼它最終會緩存整個視頻。現在它只在當前位置前緩存一點。由於視頻的放棄率,這節省了大量的帶寬。

您可以將部分文件寫入磁盤或將其保存在內存中。

+1

這並沒有真正解決被問到的問題。 –

+0

如果它解釋了「*他們永遠不會從第一個地方開始*」,這個*可能*是一個很好的答案。但是,該工具確實從任意URL下載,因此服務器不支持它。 –