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

C# HttpClient-下载前下载文件的大小,c#,windows-runtime,windows-store-apps,dotnet-httpclient,C#,Windows Runtime,Windows Store Apps,Dotnet Httpclient,我正在用进度条实现文件下载。具体地说,我在这个问题上使用了IAsyncOperationWithProgress。它工作得很好,但我只收到接收/下载的字节数。但我需要计算百分比部分来显示进度。这意味着我需要知道下载开始时的总字节数,但我没有找到有效的方法 下面的代码解析进度报告。我尝试使用responseStream.length获取流长度,但抛出错误“此流不支持搜索操作” static async Task<byte[]> GetByteArratTaskProvider(Task

我正在用进度条实现文件下载。具体地说,我在这个问题上使用了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();
        }
静态异步任务GetByteArratTaskProvider(任务httpOperation、CancellationToken令牌、IProgress progressCallback)
{
整数偏移=0;
int streamLength=0;
var result=新列表();
var responseBuffer=新字节[500];
//执行http请求并获得初始响应
//注意:此处可能会收到网络错误
var httpInitialResponse=等待httpOperation;
使用(var responseStream=await httpInitialResponse.Content.ReadAsStreamAsync())
{
int-read;
做
{
if(令牌.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
read=wait responseStream.ReadAsync(responseBuffer,0,responseBuffer.Length);
结果.AddRange(responseBuffer);
偏移量+=读取;
//这里我想发送下载数据的百分比
//偏移量/(总尺寸/100)
三、报告(抵销);
}while(read!=0);
}
返回result.ToArray();
}

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

您可以查看服务器返回的内容长度头的值,该值存储在您的案例中的
httpInitialResponse.Content.Headers
。您必须在集合中找到具有相应键(即“内容长度”)的标题

例如,您可以这样做:

int length = int.Parse(httpInitialResponse.Content.Headers.First(h => h.Key.Equals("Content-Length")).Value.First());
(您必须首先确保服务器已发送内容长度头,否则上面的行将出现异常并失败)

您的代码如下所示:

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();
}
静态异步任务GetByteArrayTaskProvider(任务httpOperation、CancellationToken令牌、IProgress进程回调)
{
整数偏移=0;
int streamLength=0;
var result=新列表();
var responseBuffer=新字节[500];
//执行http请求并获得初始响应
//注意:此处可能会收到网络错误
var httpInitialResponse=等待httpOperation;
var totalValueAsString=httpInitialResponse.Content.Headers.SingleOrDefault(h=>h.Key.Equals(“内容长度”)?.Value?.First();
int?totalValue=totalValueAsString!=null?int.Parse(totalValueAsString):null;
使用(var responseStream=await httpInitialResponse.Content.ReadAsStreamAsync())
{
int-read;
做
{
if(令牌.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
read=wait responseStream.ReadAsync(responseBuffer,0,responseBuffer.Length);
结果.AddRange(responseBuffer);
偏移量+=读取;
if(totalSize.HasValue)
{
progressCallback.Report(偏移量*100/总大小);
}
//对于其他方法,您可以发回偏移量,但此方法内外的代码都会变得复杂。“支持进度报告”的逻辑应该在其他地方,以保持方法简单和非多用途(我将创建一个用于字节进度的方法,另一个用于百分比进度的方法)
}while(read!=0);
}
返回result.ToArray();
}

非常感谢。我试图从标题中获取内容长度,但我是从
httpInitialResponse.Headers
而不是
httpInitialResponse.Content.Headers
中尝试的。这是我的问题。任何人都可以编辑代码以便可以轻松地复制和粘贴吗?请记住,如果HTTP响应被压缩,您将获得压缩的大小。