C#使用HttpClient對大文件進(jìn)行斷點(diǎn)上傳和下載
什么是Http的斷點(diǎn)上傳和下載
斷點(diǎn)上傳:在向服務(wù)商上傳大文件的時(shí)候,將一個(gè)大的文件拆分成多個(gè)小的文件,每個(gè)文件通過單獨(dú)的Http請求上傳給服務(wù)器。
斷點(diǎn)下載:在向服務(wù)器請求下載一個(gè)大的資源文件的時(shí)候,不是一次Http請求返回所有的資源文件內(nèi)容。而是先通過Head請求,拿到資源文件的大?。▎挝唬鹤止?jié))。然后每次請求只請求一部分字節(jié)的數(shù)據(jù),將請求到的數(shù)據(jù)在本地進(jìn)行拼接。
斷點(diǎn)上傳和下載的優(yōu)點(diǎn)
1、避免網(wǎng)絡(luò)中斷時(shí),重傳所有資源文件內(nèi)容。
2、提高服務(wù)器并發(fā),防止單個(gè)客戶端長時(shí)間和服務(wù)器保持連接。
3、可以實(shí)時(shí)顯示上傳和下載的進(jìn)度。
斷點(diǎn)上傳和下載的缺點(diǎn)
1、占用更多的網(wǎng)絡(luò)帶寬,因?yàn)槊看蜨ttp請求都會(huì)附帶各種額外的信息。
2、上傳和下載的時(shí)間會(huì)變得長一點(diǎn),因?yàn)槭峭ㄟ^多次請求來完成斷點(diǎn)上傳和下載。
實(shí)現(xiàn)基本原理
依賴Http協(xié)議的幾個(gè)基本的協(xié)議頭來完成斷點(diǎn)上傳和下載。
1、Content-Range
:這是一個(gè)響應(yīng)頭,表示請求的資源文件大小,我們可以通過Head請求拿到的資源文件的字節(jié)數(shù),就是讀取的這個(gè)字段。
2、Range
:這是一個(gè)請求頭,表示客戶端要請求的數(shù)組的范圍。如如:"0-1000"、"1001-2000"、"2001-3000"等,服務(wù)器接收到這個(gè)請求頭之后,只給我們返回對應(yīng)范圍內(nèi)的資源字節(jié)數(shù)組,不會(huì)把所有的字節(jié)數(shù)都返回給我們。
一般請求下,這兩個(gè)請求頭就可以實(shí)現(xiàn)簡單的斷點(diǎn)上傳和下載。本篇文章我們使用一個(gè)WPF項(xiàng)目演示斷點(diǎn)下載。
string url = "http://file.cshelloworld.com/images/1771477326069108736.jpg"; long totalSize = 0;//文件總大小 long downLoadingSize = 0;//當(dāng)前已經(jīng)下載了多少 private void Button_Click(object sender, RoutedEventArgs e) { Task.Run(async () => { //獲取到文件總大小 通過head請求 using HttpClient client = new HttpClient(); HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url); var response = await client.SendAsync(requestMessage); totalSize = response.Content.Headers.ContentLength.Value; using FileStream fileStream = new FileStream("d:\a.jpj", FileMode.Create, FileAccess.Write, FileShare.Read); //開始分片下載 while (downLoadingSize < totalSize) { //組裝range 0,1000 1000,2000 0,9999 long start = downLoadingSize; long end = start + 1000; if (end > (totalSize - 1)) { end = totalSize - 1; } client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end); var res = await client.GetAsync(url); byte[] bytes = await res.Content.ReadAsByteArrayAsync(); await fileStream.WriteAsync(bytes, 0, bytes.Length); //更新UI的進(jìn)度 downLoadingSize += bytes.Length; int process = (int)((downLoadingSize / (decimal)totalSize) * 100); this.Dispatcher.Invoke(() => { cont.Text = process + "%"; this.processBar.Value = process; }); } fileStream.Close(); }); }
在以上代碼中,首先是Head請求獲取資源文件大小。
我們主要通過以下代碼實(shí)現(xiàn),通過設(shè)置HttpMethod.Head
構(gòu)建一個(gè)HttpRequestMessage
的請求對象
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url);
其次是斷點(diǎn)下載過程中,Range請求頭如何設(shè)置:
client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);
每次請求到字節(jié)數(shù)組之后,我們將字節(jié)數(shù)組寫入到本地的文件流中,如果網(wǎng)絡(luò)斷開,下次請求的時(shí)候,讀取本地文件大小,假設(shè)本地未見大小為1000,那么我們請求的時(shí)候Range就從1001開始,這樣服務(wù)器就給我們返回的是1001之后的字節(jié)數(shù)組了。
當(dāng)然在這個(gè)過程中,我們還要考慮一個(gè)問題,如果服務(wù)器的資源文件發(fā)生了修改會(huì)怎么樣。如果我們繼續(xù)下載的話 ,就會(huì)出現(xiàn)問題。因?yàn)榭蛻舳讼螺d的文件都不是同一個(gè)文件。這種情況下,我們可以使用Http的請求頭Last-Modified
來判斷文件是否修改,這個(gè)請求頭表示文件的最近一次修改時(shí)間。當(dāng)我們第一次請求數(shù)據(jù)的時(shí)候可以把這個(gè)請求頭的時(shí)間記錄下來,后續(xù)請求如果服務(wù)器資源文件發(fā)生變化,我們就將本地文件全部刪除,然后重新發(fā)起請求。
以上就是C#使用HttpClient對大文件進(jìn)行斷點(diǎn)上傳和下載的詳細(xì)內(nèi)容,更多關(guān)于C# HttpClient文件上傳和下載的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#編程實(shí)現(xiàn)帶有Aero效果的窗體示例
這篇文章主要介紹了C#編程實(shí)現(xiàn)帶有Aero效果的窗體,涉及C#調(diào)用動(dòng)態(tài)鏈接庫針對窗體屬性的相關(guān)操作技巧,需要的朋友可以參考下2017-07-07C#科學(xué)繪圖之使用scottPlot繪制多個(gè)圖像
ScottPlot是基于.Net的一款開源免費(fèi)的交互式可視化庫,支持Winform和WPF等UI框架,本文主要為大家詳細(xì)介紹了如何使用scottPlot實(shí)現(xiàn)繪制多個(gè)圖像,需要的可以參考下2023-12-12