HttpClient 部分下载

问题描述

修改在这里找到的代码> https://gist.github.com/subena22jf/3358b8609966203502a5

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Net;

namespace DownloadMultipart
{
    class Program
    {
        static void Main(string[] args)
        {
            Task.Run(() => new Downloader().Download(
                "url_to_download","file_path_to_save"
                )).Wait();

            Console.Read();
        }
    }
    public class Downloader
    {
        const int BUFFER_SIZE = 10240;
        public async Task Download(string url,string saveAs)
        {
            using (var httpClient = new HttpClient())
            using (var request = new HttpRequestMessage(HttpMethod.Get,url))
            {
                request.Headers.Range = new RangeHeaderValue(0,255); // bugfix for 2147483647 exception [ max buffer size => int.MaxValue ]
                // why not HttpCompletionoption.ResponseHeadersRead ?
                // because it will respond 200 only,you won't get partial/206 response
                using (var response = await httpClient.SendAsync(request))
                {
                    File.Create(saveAs).dispose();
                    if (response.StatusCode == HttpStatusCode.PartialContent)
                    {
                        var contentLength = response.Content.Headers.ContentRange?.Length ?? 0;
                        const double numberOfParts = 5.0;
                        var tasks = new List<Task>();
                        var partSize = (long)Math.Ceiling(contentLength / numberOfParts);
                        for (var i = 0; i < numberOfParts; i++)
                        {
                            var start = i * partSize + Math.Min(1,i);
                            var end = Math.Min((i + 1) * partSize,contentLength);

                            tasks.Add(Task.Run(() => DownloadPart(url,saveAs,start,end)));
                        }

                        await Task.WhenAll(tasks);
                    }
                    else if (response.StatusCode == HttpStatusCode.OK)
                    {
                        await Task.Run(() => DownloadPart(url,saveAs));
                    }
                }
            }
        }

        private async void DownloadPart(string url,string saveAs,long? start = null,long? end = null)
        {
            using (var httpClient = new HttpClient())
            using (var fileStream = new FileStream(saveAs,FileMode.Open,FileAccess.Write,FileShare.Write))
            {
                var message = new HttpRequestMessage(HttpMethod.Get,url);
                if (start.HasValue)
                {
                    message.Headers.Range = new RangeHeaderValue(start,end);
                    fileStream.Position = start.Value;
                }

                Console.WriteLine($"{start}-{end} Started");
                using (var response = await httpClient.SendAsync(message,HttpCompletionoption.ResponseHeadersRead))
                using (var inputStream = await response.Content.ReadAsstreamAsync())
                {
                    int bytesRead = 0;
                    do
                    {
                        var buffer = new byte[BUFFER_SIZE];
                        bytesRead = await inputStream.ReadAsync(buffer,buffer.Length).ConfigureAwait(false);
                        await fileStream.WriteAsync(buffer,bytesRead).ConfigureAwait(false);
                    }
                    while (bytesRead > 0);
                }
                Console.WriteLine($"{start}-{end} Downloaded");
            }
        }
    }
}

我在 StackOverFlow 中阅读了大量文章和问题,但我的问题没有得到任何答案。 这些文章和问题大部分都与 WEB API 相关,所以我的问题也没有得到任何答案,因为它与 WEB API 无关。

我知道可重用的 HttpClient 有很多好处,但它不足以部分下载文件(纠正我,如果我错了)。

我有多个关于 HttpClient 的问题。

  1. 正如我所见,HttpClient 无法处理多个请求,它会将它们排入队列。对吗?
  2. 如果第一个问题是真的,通过为每个下载连接使用 HttpClient 创建多个实例是否符合逻辑? (如下图)
  3. 我们不能强制 HttpClient 在不排队的情况下处理请求吗?
  4. 使用多个 HttpClient 实例(我认为主要与 I/O 操作有关)使用大量 cpu、内存甚至电源,是否有可能以某种方式减少这些资源?
  5. 将它们下载到多个文件并在所有任务完成后合并它们是否是一个不错的选择?如果是,你能说出原因吗?

提前致谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)