.NET Core 中使用多執行緒或非同步操作來實現分片下載

ProZkb發表於2024-06-07
private static async Task DownloadFileAsync(string url, int numChunks)
{
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode();
        long fileSize = response.Content.Headers.ContentLength ?? 0;

        long chunkSize = fileSize / numChunks;
        long remainingBytes = fileSize;

        for (int i = 0; i < numChunks; i++)
        {
            long startPosition = i * chunkSize;
            long endPosition = (i == numChunks - 1) ? fileSize - 1 : (startPosition + chunkSize - 1);

            await DownloadChunkAsync(client, url, startPosition, endPosition, i);
        }
    }
}

private static async Task DownloadChunkAsync(HttpClient client, string url, long startPosition, long endPosition, int chunkIndex)
{
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
    request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(startPosition, endPosition);

    HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
    response.EnsureSuccessStatusCode();

    using (Stream contentStream = await response.Content.ReadAsStreamAsync())
    using (FileStream fileStream = new FileStream($"chunk{chunkIndex}.dat", FileMode.Create, FileAccess.Write))
    {
        await contentStream.CopyToAsync(fileStream);
    }
}

private static async Task CombineFileAsync(string url, int numChunks)
{
    string outputFilePath = "output.png"; // 輸出檔案路徑
    using (FileStream output = new FileStream(outputFilePath, FileMode.Create, FileAccess.Write))
    {
        for (int i = 0; i < numChunks; i++)
        {
            string chunkFilePath = $"chunk{i}.dat";
            byte[] chunkData = File.ReadAllBytes(chunkFilePath);
            await output.WriteAsync(chunkData, 0, chunkData.Length);
            File.Delete(chunkFilePath); // 刪除合併後的片段檔案
        }
    }
}

 private static async Task Main(string[] args)
 {
     {
         string url = "https://gips0.baidu.com/it/u=1690853528,2506870245&fm=3028&app=3028&f=JPEG&fmt=auto?w=1024&h=1024"; // 要下載的檔案 URL
         int numChunks = 4; // 分成的片段數量

         await DownloadFileAsync(url, numChunks);
         await CombineFileAsync(url, numChunks);
     }
}

首先確定要下載的檔案的大小,然後將檔案分成指定數量的塊。接著,我們針對每個塊傳送 HTTP 請求,使用 Range 頭部指定下載的範圍。每個塊的資料都將非同步寫入到一個單獨的檔案中。

最後,可以根據需要將所有塊合併成完整的檔案。

透過分片下載,我們可以同時下載多個檔案片段,以充分利用頻寬和資源,提高下載速度

首先透過 DownloadFileAsync 方法下載檔案的各個片段,然後在 CombineFileAsync 方法中將這些片段合併為一個完整的檔案。在合併檔案時,我們首先開啟一個輸出檔案流,然後逐個讀取每個片段檔案的內容並寫入輸出檔案流。最後,我們刪除了合併後不再需要的片段檔案。

相關文章