C# 文件下載之斷點續傳完成代碼。本站提示廣大學習愛好者:(C# 文件下載之斷點續傳完成代碼)文章只能為提供參考,不一定能成為您想要的結果。以下是C# 文件下載之斷點續傳完成代碼正文
留意,本文所說的斷點續傳特指 HTTP 協議中的斷點續傳。本文次要聊聊思緒和關鍵代碼,更多細節請參考本文附帶的 demo。
任務原理
HTTP 協議中定義了一些懇求/呼應頭,經過組合運用這些頭信息。我們可以在一次 HTTP 懇求中只懇求一個文件中的一局部數據。這樣我們就可以把曾經下載的數據存起來,下次只用懇求剩余的數據即可,當全部數據都下載到本地後再完成兼並任務。
HTTP 協議指出,可以經過 HTTP 懇求中的 Range 頭指定懇求數據的范圍,Range 頭的運用也很復雜,只需指定上面的格式就可以了:
Range: bytes=500-999
它的意思是,只懇求目的文件的第 500 到第 999 這 500 個字節。
比方我有一個1000 bytes 大小的文件需求下載,第一次懇求時不必指定 Range 頭,表示下載整個文件。但在下載完第 499 個字節後,下載被取消了。那麼在下一次懇求下載同一個文件時,只需求下載第 500 個字節至第 999 個字節的數據就可以了。原理看上去很復雜,但我們需求思索上面幾個問題:
1.是不是一切的 web 服務器都支持 Range 頭?
2.屢次懇求之間能夠會距離很長的時間,服務器上的文件發作了變化怎樣辦?
3.如何保管下載的局部數據和相關信息?
4.當我們經過字節操作把一個文件拼成原始大小後,如何驗證它和源文件如出一轍?
上面我們就帶著這些問題去探求斷點續傳的一些細節。
反省服務器端對斷點續傳的支持
在服務器呼應我們的懇求時,會在呼應頭中經過 Accept-Ranges 指明能否承受懇求一個資源的一局部數據。但這裡似乎有個小小的圈套,就是不同的服務器能夠前往不同的值來指明自己可以承受局部資源的懇求。貌似比擬一致的辦法是,當服務器不支持懇求局部數據時,都會前往 Accept-Ranges: none,我們只需判別這個前往值是不是等於 none 就行了。代碼如下:
private static bool IsAcceptRanges(WebResponse res) { if (res.Headers["Accept-Ranges"] != null) { string s = res.Headers["Accept-Ranges"]; if (s == "none") { return false; } } return true; }
反省服務器端文件能否變化
當我們下載了一個文件的一局部之後,能夠馬上就會接著下載,也能夠會過一段時間再下載,也能夠永遠不會再接著下載了…
這裡的問題是,當下主要接著下載時,如何確定服務器上的文件還是現在下載了一半的那個文件。假如服務器上的文件曾經更新了,那無論如何都需求重新從頭開端下載。只要在服務器上的文件沒有發作變化的狀況下,斷點續傳才有意義。
關於這個問題,HTTP 呼應頭為我們提供了不同的選擇。ETag 和 Last-Modified 都能完成義務。
先看 ETag:
The ETag response-header field provides the current value of the entity tag for the requested variant. (引自RFC2616 14.19 ETag)
復雜點說 ETag 就是一個標識以後懇求內容的字符串,當懇求的資源發作變化後,對應的 ETag 也會變化。好了,最復雜的方法是第一次懇求時,把呼應頭中的 ETag 存上去,下次懇求時做比擬。代碼如下:
string newEtag = GetEtag(response); // tempFileName指曾經下載到本地的局部文件內容 // tempFileInfoName指保管了Etag內容的暫時文件 if (File.Exists(tempFileName) && File.Exists(tempFileInfoName)) { string oldEtag = File.ReadAllText(tempFileInfoName); if (!string.IsNullOrEmpty(oldEtag) && !string.IsNullOrEmpty(newEtag) && newEtag == oldEtag) { // Etag沒有變化,可以斷點續傳 resumeDowload = true; } } else { if (!string.IsNullOrEmpty(newEtag)) { File.WriteAllText(tempFileInfoName, newEtag); } } private static string GetEtag(WebResponse res) { if (res.Headers["ETag"] != null) { return res.Headers["ETag"]; } return null; }
再來看看 Last-Modified:
The Last-Modified entity-header field indicates the date and time at which the origin server believes the variant was last modified. (引自RFC2616 14.29 Last-Modified)
Last-Modified 就是所懇求的資源在服務器上的最後一次修正時間。運用辦法和 ETag 大體相反。
團體覺得運用 ETag 和 Last-Modified 中的任何一個都能到達我們的目的。但是你也可以兩個都用,做 double check,誰知道web服務器的完成是不是嚴厲遵照了 HTTP 協議!
保管兩頭後果
這裡次要就是用 C# 停止文件操作。大體思緒是假如有未下載完的文件,就把新下載的字節添加到文件的末尾,不再啰嗦,有興味的同窗請直接看 demo 代碼。
驗證文件
在斷點續傳的進程中,我們以 byte 為單位下載、兼並文件,假如整個進程中稍有沒有處置好的異常,能夠最後失掉的文件就和源文件不太一樣。因而最好是可以對下載好的文件停止一次校驗。可這也是最難、最不容易完成的。由於它需求服務器端的支持,比方服務器端在提供一個可下載文件的同時提供該文件的 MD5 hash。當然,假如服務器端也是我們自己創立的,我們就可以去完成它。但我們又怎樣可以要求現存的 web 服務器都提供這樣的功用呢!
Demo 下載
以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支持。