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

Joz*_*sky 6 c# windows-runtime dotnet-httpclient windows-store-apps

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

以下代码解析进度报告.我尝试使用responseStream.Length获取流长度,但错误"此流不支持搜索操作".被扔了.

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();
        }
Run Code Online (Sandbox Code Playgroud)

你知道如何处理这个问题吗?或者您是否有其他方式如何通过HttpClient下载具有进度报告的文件?我也尝试使用BackgroundDownloader,但这对我来说还不够.谢谢.

小智 7

您可以查看服务器返回的Content-Length标头的值,该标头存储在您的案例中httpInitialResponse.Content.Headers.您必须使用相应的键(即"Content-Length")在集合中找到标题

你可以这样做,例如:

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

(您必须首先确保服务器已发送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();
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢.我试图从Headers获取Content-Length,但是我从`httpInitialResponse.Headers`而不是`httpInitialResponse.Content.Headers`尝试了它.这是我的问题. (2认同)