.NET Core 中使用多线程或异步操作来实现分片下载

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 方法中将这些片段合并为一个完整的文件。在合并文件时,我们首先打开一个输出文件流,然后逐个读取每个片段文件的内容并写入输出文件流。最后,我们删除了合并后不再需要的片段文件。

 

posted @ 2024-06-07 00:24  ProZkb  阅读(34)  评论(0编辑  收藏  举报