如何在HttpClient下载GitHub仓库时获取实时已下载字节数?
实现GitHub仓库下载进度实时显示
要实时查看已下载字节数,GetByteArrayAsync无法满足需求——它会将完整响应一次性读入内存,且不暴露中间下载进度。可以通过手动读取响应流的方式实现,核心思路如下:
- 先获取响应头,拿到文件总大小(若服务器返回
Content-Length) - 分块读取响应流,每读取一块就更新已下载字节数并输出进度
修改后的代码如下:
using System; using System.IO; using System.Net.Http; using System.Text; using System.Threading.Tasks; public async Task<byte[]> DownloadWithProgress(string url, string githubToken) { using var client = new HttpClient(); // 配置GitHub Basic认证 var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{githubToken}:")); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", credentials); // 先获取响应头,不等待完整内容下载 using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); // 获取总文件大小(服务器未返回则显示未知) long totalBytes = response.Content.Headers.ContentLength ?? -1; long downloadedBytes = 0; // 用内存流存储最终下载内容 using var memoryStream = new MemoryStream(); using var responseStream = await response.Content.ReadAsStreamAsync(); // 分块读取流,每次读取8KB缓冲区 var buffer = new byte[8192]; int bytesRead; while ((bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length)) > 0) { await memoryStream.WriteAsync(buffer, 0, bytesRead); downloadedBytes += bytesRead; // 实时刷新进度显示 Console.Clear(); if (totalBytes > 0) { double progress = (double)downloadedBytes / totalBytes * 100; Console.WriteLine($"已下载: {downloadedBytes:N0} / {totalBytes:N0} 字节 ({progress:F2}%)"); } else { Console.WriteLine($"已下载: {downloadedBytes:N0} 字节 (总大小未知)"); } } Console.WriteLine("\n下载完成"); return memoryStream.ToArray(); }
关键说明
HttpCompletionOption.ResponseHeadersRead:让HttpClient在拿到响应头后立即返回,无需等待整个文件下载完成,以此提前获取总文件大小- 分块读取:用8KB缓冲区循环读取流,避免一次性占用过多内存,同时能实时更新下载进度
- 兼容总大小未知场景:若服务器采用分块传输未返回
Content-Length,则仅显示已下载字节数
调用时直接在异步方法中使用await DownloadWithProgress(你的仓库URL, GitHub令牌);即可。
内容的提问来源于stack exchange,提问作者user13525259
相关产品推荐
相关产品推荐

