上传至Azure Blob容器的文件大小与原始文件不符问题求助
问题根因
你的代码存在几个核心逻辑错误,直接导致大文件仅上传了部分数据:
- 未校验文件流读取的实际字节数
FileStream.Read()方法不保证每次都返回你请求的bytesToRead长度的数据,实际返回值才是本次读取到的有效字节数,你直接忽略该返回值,默认读取到了完整的块长度。一旦某次读取返回的字节数小于请求值,你后续仍按完整块大小更新bytesToUpload等计数变量,会导致计数提前归零,循环提前终止,仅上传了部分数据。你最终得到的3.12GB文件刚好是100个32MB块的总大小,说明循环仅执行了100次就提前退出。 - 异步操作无异常校验和重试机制
你调用的PutBlockAsync是异步方法,仅通过ContinueWith执行后续逻辑,但完全没有判断异步任务的执行状态,一旦某个块因为网络波动、存储配额不足、权限不足等原因上传失败,你没有任何感知,仍继续执行后续流程,最终提交的块列表中会缺失对应块,或存在无效块。 - 异步方法未做等待逻辑
你的方法名义上是异步方法,但返回值为void,所有异步操作都没有暴露等待入口,外部调用该方法时很容易在所有块上传、块列表提交操作完成前就结束进程,导致上传流程中途中断。 - 不必要的文件流重复打开
你每次循环都重新打开一次本地文件,频繁打开100GB级别的大文件会大幅提升IO异常概率,也会严重拖累上传性能,全程复用一个文件流即可。
修复后的核心逻辑参考
// 建议改成异步方法返回Task public async Task UploadStreamAsync(string file) { var fileInfo = new FileInfo(file); CloudBlockBlob myBlob = _container.GetBlockBlobReference(fileInfo.Name); var blockSize = 32 * 1024 * 1024; myBlob.StreamWriteSizeInBytes = blockSize; long bytesToUpload = fileInfo.Length; List<string> blockIds = new List<string>(); int index = 1; // 复用同一个文件流 using (FileStream fs = new FileStream(fileInfo.FullName, FileMode.Open, FileAccess.Read)) { while (bytesToUpload > 0) { var bytesToRead = (int)Math.Min(blockSize, bytesToUpload); var blobContents = new byte[bytesToRead]; // 校验实际读取的字节数 int bytesRead = await fs.ReadAsync(blobContents, 0, bytesToRead); if (bytesRead == 0) break; // 读取到文件末尾 var blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(index.ToString("d6"))); blockIds.Add(blockId); // 等待块上传完成,可自行补充异常重试逻辑 using (var ms = new MemoryStream(blobContents, 0, bytesRead)) { await myBlob.PutBlockAsync(blockId, ms, null); } bytesToUpload -= bytesRead; double percentComplete = (double)(fileInfo.Length - bytesToUpload) / (double)fileInfo.Length; _logger.LogInformation("Percent complete = {Percent}", percentComplete.ToString("P")); index++; } } // 等待块列表提交完成 await myBlob.PutBlockListAsync(blockIds); _logger.LogInformation("Blob uploaded completely."); }
内容的提问来源于stack exchange,提问作者skeferstat
相关产品推荐
相关产品推荐

