.net8 下载文件+进度条

效果:

代码:
1、异步下载代码

展开或折叠代码
 public async Task DownloadFileAsync(string url, string savePath, IProgress<FileDownloadInfo> progress, CancellationToken cancelToken)
 {
     using HttpClient client = new();
     //指定HttpCompletionOption.ResponseHeadersRead来立即处理响应头而不是等待内容完全下载
     using HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancelToken);

     using Stream stream = await response.Content.ReadAsStreamAsync(cancelToken);
     using FileStream fileStream = new(savePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true);

     //TCP/IP协议数据包通常也是8kb,所以buffer的长度与之匹配。
     byte[] buffer = new byte[8192];
     int bytesRead;
     long totalBytesRead = 0;
     long totalBytes = response.Content.Headers.ContentLength ?? -1;

     var stopwatch = new Stopwatch();
     stopwatch.Start();

     while (!cancelToken.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, cancelToken)) > 0)
     {
         await fileStream.WriteAsync(buffer.AsMemory(0, bytesRead), cancelToken);
         totalBytesRead += bytesRead;

         double speed = 0;
         if (stopwatch.Elapsed.TotalSeconds > 0)
         {
             speed = totalBytesRead / stopwatch.Elapsed.TotalSeconds;
         }

         var value = (int)(((double)totalBytesRead / totalBytes) * 100);
         progress.Report(new FileDownloadInfo
         {
             Size = totalBytes,
             Downloaded = totalBytesRead,
             Progress = value,
             Speed = speed,
             Remaining = (int)((totalBytes - totalBytesRead) / speed)
         });
     }
     cancelToken.ThrowIfCancellationRequested();
 } 

2、创建一个文件下载信息类

展开或折叠代码
public class FileDownloadInfo : IDisposable
{
    /// <summary>
    /// 文件大小
    /// </summary>
    public long Size { get; set; }
    /// <summary>
    /// 已下载
    /// </summary>
    public long Downloaded { get; set; }
    /// <summary>
    /// 下载速度
    /// </summary>
    public double Speed { get; set; }
    /// <summary>
    /// 下载进度
    /// </summary>
    public int Progress { get; set; }
    /// <summary>
    /// 预计剩余时间
    /// </summary>
    public int Remaining { get; set; }

    public void Dispose()
    {
        GC.SuppressFinalize(this);
    }
}
3、如何调用

    3.1、定义一个Progress

展开或折叠代码
var progress = new Progress<FileDownloadInfo>(info =>
{
    //todo 处理异步方法中Report过来的数据,比如下载进度、下载速度等。
});
    3.2、使用await等待前面的异步方法
展开或折叠代码
await DownloadFileAsync(url, path, progress, _cancellationTokenSource.Token);
4、中途取消下载

    4.1、定义一个取消令牌

展开或折叠代码
private CancellationTokenSource? _cancellationTokenSource = new CancellationTokenSource();

    4.2、调用异步下载方法时传入令牌。

    4.3、在需要取消下载的时候调用令牌的Cancel()方法

展开或折叠代码
_cancellationTokenSource?.Cancel();
posted @ 2024-09-04 15:04  牛仔很肥  阅读(285)  评论(0)    收藏  举报