C#使用Microsoft.Azure.Storage.DataMovement下载Azure Blob 2GB以上大文件失败如何解决
大文件下载失败解决方案
你遇到的超时、任务取消、I/O中止三类错误,核心是GB级文件传输时长超过了SDK默认阈值、缺少容错机制,同时原有代码存在配置未生效的问题,具体优化方案如下:
核心问题修正
原有代码实例化了DownloadOptions但调用TransferManager.DownloadAsync时传入了null,所有下载配置完全未生效,是首要导致大文件下载失败的原因。
具体优化措施
- 调整Blob客户端全局配置:给CloudBlobClient设置更长的单次请求超时,开启指数退避重试策略,应对网络波动
- 调整DataMovement库核心参数:增大块大小,根据网络情况调整并行下载数,避免大量小请求导致的超时
- 配置下载超时规则:设置整个下载任务的最大执行时间,覆盖GB级文件的全量下载周期
- 启用断点续传:持久化保存传输checkpoint,传输中断后可直接从断点续传,无需重新下载全量文件
- 新增异常捕获逻辑:捕获传输过程中的错误,留存断点信息方便后续续传
优化后代码
using Microsoft.Azure.Storage; using Microsoft.Azure.Storage.Blob; using Microsoft.Azure.Storage.DataMovement; using Microsoft.Azure.Storage.RetryPolicies; using System; using System.IO; using System.Threading; using System.Threading.Tasks; namespace SampleDownload { class Program { // 断点保存路径,传输中断后下次启动自动读取续传 private static string _checkpointPath = @"D:\transfer_checkpoint.dat"; static async Task Main(string[] args) { string accountName = ""; string accountKey = ""; string storageConnectionString = "DefaultEndpointsProtocol=https;AccountName=" + accountName + ";AccountKey=" + accountKey; CloudStorageAccount account = CloudStorageAccount.Parse(storageConnectionString); await Download(account); } public static async Task<CloudBlockBlob> GetBlob(CloudStorageAccount account) { CloudBlobClient blobClient = account.CreateCloudBlobClient(); // 配置Blob客户端超时与重试策略 blobClient.DefaultRequestOptions = new BlobRequestOptions { MaximumExecutionTime = TimeSpan.FromHours(1), // 单个请求最大执行时间 ServerTimeout = TimeSpan.FromMinutes(30), // 服务端超时时间 RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(5), 5) // 指数退避重试,最多重试5次 }; Console.WriteLine("\nProvide name of Blob container:"); string containerName = Console.ReadLine(); CloudBlobContainer container = blobClient.GetContainerReference(containerName); await container.CreateIfNotExistsAsync(); // 替换原有Wait()避免死锁 Console.WriteLine("\nProvide name of Blob:"); string blobName = Console.ReadLine(); CloudBlockBlob blob = container.GetBlockBlobReference(blobName); return blob; } public static async Task Download(CloudStorageAccount account) { string path = @"D:\test.zip"; Console.WriteLine("\nTransfer started..."); // 配置下载参数 DownloadOptions downloadOptions = new DownloadOptions { MaximumExecutionTime = TimeSpan.FromHours(24), // 整个下载任务最大执行时间,可根据文件大小调整 DisableContentMD5Validation = true // 大文件可关闭MD5校验加快速度,需要校验可设为false }; // 读取本地留存的断点(如果存在) TransferCheckpoint checkpoint = null; if (File.Exists(_checkpointPath)) { using (FileStream fs = File.OpenRead(_checkpointPath)) { checkpoint = TransferCheckpoint.Deserialize(fs); } } SingleTransferContext transferContext = GetSingleTransferContext(checkpoint); CloudBlockBlob sourceObject = await GetBlob(account); // 配置DataMovement库核心参数 TransferManager.Configurations.BlockSize = 8 * 1024 * 1024; // 单个块大小设为8MB,大文件可调整到16-32MB TransferManager.Configurations.ParallelOperations = 16; // 并行下载数,根据带宽情况调整,带宽大可设到32 try { // 注意这里传入了downloadOptions,原有代码传了null导致配置未生效 await TransferManager.DownloadAsync(sourceObject, path, downloadOptions, transferContext, CancellationToken.None); // 下载完成后删除断点文件 if (File.Exists(_checkpointPath)) { File.Delete(_checkpointPath); } Console.WriteLine("\nTransfer operation complete."); } catch (Exception ex) { // 传输出错时保存当前断点 Console.WriteLine($"\nTransfer failed: {ex.Message}"); using (FileStream fs = File.OpenWrite(_checkpointPath)) { transferContext.LastCheckpoint.Serialize(fs); } Console.WriteLine("Checkpoint saved, next run will resume from current progress."); throw; } } public static SingleTransferContext GetSingleTransferContext(TransferCheckpoint checkpoint) { SingleTransferContext context = new SingleTransferContext(checkpoint); context.ProgressHandler = new Progress<TransferStatus>((progress) => { Console.Write("\rBytes transferred: {0}", progress.BytesTransferred); }); return context; } } }
内容的提问来源于stack exchange,提问作者bharat
相关产品推荐
相关产品推荐

