C#如何使用HttpClient對大檔案進行斷點上傳和下載

caoruipeng發表於2024-06-23

什麼是Http的斷點上傳和下載

斷點上傳:在向服務商上傳大檔案的時候,將一個大的檔案拆分成多個小的檔案,每個檔案透過單獨的Http請求上傳給伺服器。

斷點下載:在向伺服器請求下載一個大的資原始檔的時候,不是一次Http請求返回所有的資原始檔內容。而是先透過Head請求,拿到資原始檔的大小(單位:位元組)。然後每次請求只請求一部分位元組的資料,將請求到的資料在本地進行拼接。

斷點上傳和下載的優點

1、避免網路中斷時,重傳所有資原始檔內容。

2、提高伺服器併發,防止單個客戶端長時間和伺服器保持連線。

3、可以實時顯示上傳和下載的進度。

斷點上傳和下載的缺點

1、佔用更多的網路頻寬,因為每次Http請求都會附帶各種額外的資訊。

2、上傳和下載的時間會變得長一點,因為是透過多次請求來完成斷點上傳和下載。

實現基本原理

依賴Http協議的幾個基本的協議頭來完成斷點上傳和下載。

1、Content-Range:這是一個響應頭,表示請求的資原始檔大小,我們可以透過Head請求拿到的資原始檔的位元組數,就是讀取的這個欄位。

2、Range :這是一個請求頭,表示客戶端要請求的陣列的範圍。如如:"0-1000"、"1001-2000"、"2001-3000"等,伺服器接收到這個請求頭之後,只給我們返回對應範圍內的資源位元組陣列,不會把所有的位元組數都返回給我們。

一般請求下,這兩個請求頭就可以實現簡單的斷點上傳和下載。本篇文章我們使用一個WPF專案演示斷點下載。

string url = "http://file.cshelloworld.com/images/1771477326069108736.jpg";
long totalSize = 0;//檔案總大小
long downLoadingSize = 0;//當前已經下載了多少

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的進度
            downLoadingSize += bytes.Length;
            int process = (int)((downLoadingSize / (decimal)totalSize) * 100);
            this.Dispatcher.Invoke(() =>
            {
                cont.Text = process + "%";
                this.processBar.Value = process;
            });
        }
        fileStream.Close();
    });
}

在以上程式碼中,首先是Head請求獲取資原始檔大小。

我們主要透過以下程式碼實現,透過設定HttpMethod.Head構建一個HttpRequestMessage的請求物件

HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url);

其次是斷點下載過程中,Range請求頭如何設定:

client.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);

每次請求到位元組陣列之後,我們將位元組陣列寫入到本地的檔案流中,如果網路斷開,下次請求的時候,讀取本地檔案大小,假設本地未見大小為1000,那麼我們請求的時候Range就從1001開始,這樣伺服器就給我們返回的是1001之後的位元組陣列了。

當然在這個過程中,我們還要考慮一個問題,如果伺服器的資原始檔發生了修改會怎麼樣。如果我們繼續下載的話 ,就會出現問題。因為客戶端下載的檔案都不是同一個檔案。這種情況下,我們可以使用Http的請求頭Last-Modified來判斷檔案是否修改,這個請求頭表示檔案的最近一次修改時間。當我們第一次請求資料的時候可以把這個請求頭的時間記錄下來,後續請求如果伺服器資原始檔發生變化,我們就將本地檔案全部刪除,然後重新發起請求。

聯絡站長

C#如何使用HttpClient對大檔案進行斷點上傳和下載

站長公眾號

C#如何使用HttpClient對大檔案進行斷點上傳和下載

推薦閱讀

  • C#棄元表示式的用法
  • 記錄一次JSON.NET反序列化帶來的記憶體爆炸問題
  • C#如何使用HttpClient對大檔案進行斷點上傳和下載
  • Windows Api如何建立一個快捷方式並且在開始選單搜尋到自己的應用
  • .NET Core配置檔案發生變更的時候,程式如何接受
  • C#如何將檔案壓縮成ZIP並且實時顯示壓縮排度
  • 線性表
  • 順序棧
  • 鏈棧
  • 陣列實現佇列

相關文章