HttpClient -下载前下载文件的大小

本文关键字:下载 HttpClient 文件 | 更新日期: 2023-09-27 18:09:38

我正在实现带有进度条的文件下载。我使用IAsyncOperationWithProgress来解决这个问题,具体来说是这个代码。它工作得很好,但我只接收到接收/下载的字节数。但是我需要计算百分比来显示进度。这意味着我需要知道下载开始时的总字节数,我没有找到有效的方法。

下面的代码解析进度报告。我试图获得流长度与responseStream。长度,但抛出错误"此流不支持查找操作"。

static async Task<byte[]> GetByteArratTaskProvider(Task<HttpResponseMessage> httpOperation, CancellationToken token, IProgress<int> progressCallback)
        {
            int offset = 0;
            int streamLength = 0;
            var result = new List<byte>();
            var responseBuffer = new byte[500];
            // Execute the http request and get the initial response
            // NOTE: We might receive a network error here
            var httpInitialResponse = await httpOperation;
            using (var responseStream = await httpInitialResponse.Content.ReadAsStreamAsync())
            {
                int read;
                do
                {
                    if (token.IsCancellationRequested)
                    {
                        token.ThrowIfCancellationRequested();
                    }
                    read = await responseStream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
                    result.AddRange(responseBuffer);
                    offset += read;
                    // here I want to send percents of downloaded data
                    // offset / (totalSize / 100)
                    progressCallback.Report(offset);
                } while (read != 0);
            }
            return result.ToArray();
        }

你知道如何处理这个问题吗?或者你有一些其他的方式如何下载文件与进度报告通过HttpClient?我试着使用BackgroundDownloader,但这对我来说还不够。谢谢你。

HttpClient -下载前下载文件的大小

您可以查看服务器返回的Content-Length报头的值,该值在您的示例中存储在httpInitialResponse.Content.Headers中。你必须在集合中找到标题与相应的键(即。内容长度)

你可以这样做,例如:

int length = int.Parse(httpInitialResponse.Content.Headers.First(h => h.Key.Equals("Content-Length")).Value.First());

(您必须首先确保服务器已经发送了一个Content-Length报头,否则上面的行将异常失败)

你的代码看起来像:

static async Task<byte[]> GetByteArrayTaskProvider(Task<HttpResponseMessage> httpOperation, CancellationToken token, IProgress<int> progressCallback)
{
    int offset = 0;
    int streamLength = 0;
    var result = new List<byte>();
    var responseBuffer = new byte[500];
    // Execute the http request and get the initial response
    // NOTE: We might receive a network error here
    var httpInitialResponse = await httpOperation;
    var totalValueAsString = httpInitialResponse.Content.Headers.SingleOrDefault(h => h.Key.Equals("Content-Length"))?.Value?.First());
    int? totalValue = totalValueAsString != null ? int.Parse(totalValueAsString) : null;
    using (var responseStream = await httpInitialResponse.Content.ReadAsStreamAsync())
    {
       int read;
       do
       {
           if (token.IsCancellationRequested)
           {
              token.ThrowIfCancellationRequested();
           }
           read = await responseStream.ReadAsync(responseBuffer, 0, responseBuffer.Length);
           result.AddRange(responseBuffer);
           offset += read;
           if (totalSize.HasValue)
           {
              progressCallback.Report(offset * 100 / totalSize);
           }
           //for else you could send back the offset, but the code would become to complex in this method and outside of it. The logic for "supports progress reporting" should be somewhere else, to keep methods simple and non-multi-purpose (I would create a method for with bytes progress and another for percentage progress)
       } while (read != 0);
    }
    return result.ToArray();
}