使用DownloadToFileParallelAsync下载大文件如何追踪下载进度?
Microsoft.Azure.Storage.DataMovement下载进度追踪可行方案
针对DownloadToFileParallelAsync方法的进度追踪需求,以下两种方案均可以保留原有下载性能,实现稳定的进度统计:
方案1:使用库内置TransferContext进度回调
该方案无额外开发成本,完全复用原有下载逻辑,性能无损耗:
- 先调用Blob的属性查询接口获取待下载文件的总字节大小
- 初始化
SingleTransferContext对象,绑定IProgress<TransferStatus>回调 - 调用
DownloadToFileParallelAsync时传入创建的TransferContext实例
代码示例:
// 获取目标文件总大小 await cloudBlob.FetchAttributesAsync(); long totalSize = cloudBlob.Properties.Length; var transferContext = new SingleTransferContext { Progress = new Progress<TransferStatus>(status => { double progress = (double)status.BytesTransferred / totalSize * 100; // 自定义进度处理逻辑 Console.WriteLine($"下载进度:{progress:F2}%"); }) }; // 执行下载,传入上下文参数 await blob.DownloadToFileParallelAsync(localPath, FileMode.Create, default, null, transferContext, default);
方案2:自定义进度统计包装Stream
如果需要更细粒度的进度控制,可以通过拦截写入流的方式统计已写入字节,性能损耗可以忽略:
- 实现自定义
ProgressStream类,包装原生FileStream,在Write方法中累计已写入字节数并触发回调 - 调用
DownloadToFileParallelAsync的Stream重载版本,传入包装后的ProgressStream对象
自定义Stream实现代码:
public class ProgressStream : Stream { private readonly Stream _baseStream; private readonly Action<long> _onWrite; private long _writtenBytes; public ProgressStream(Stream baseStream, Action<long> onWriteCallback) { _baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); _onWrite = onWriteCallback ?? throw new ArgumentNullException(nameof(onWriteCallback)); } public override void Write(byte[] buffer, int offset, int count) { _baseStream.Write(buffer, offset, count); _writtenBytes += count; _onWrite(_writtenBytes); } // 其余Stream成员直接转发到基础流实现即可 public override bool CanRead => _baseStream.CanRead; public override bool CanSeek => _baseStream.CanSeek; public override bool CanWrite => _baseStream.CanWrite; public override long Length => _baseStream.Length; public override long Position { get => _baseStream.Position; set => _baseStream.Position = value; } public override void Flush() => _baseStream.Flush(); public override int Read(byte[] buffer, int offset, int count) => _baseStream.Read(buffer, offset, count); public override long Seek(long offset, SeekOrigin origin) => _baseStream.Seek(offset, origin); public override void SetLength(long value) => _baseStream.SetLength(value); }
使用示例:
await cloudBlob.FetchAttributesAsync(); long totalSize = cloudBlob.Properties.Length; await using var baseFs = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None); await using var progressFs = new ProgressStream(baseFs, writtenBytes => { double progress = (double)writtenBytes / totalSize * 100; Console.WriteLine($"下载进度:{progress:F2}%"); }); await blob.DownloadToFileParallelAsync(progressFs, default, null, default, default);
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

