Blazor WebAssembly纯C#实现大文件分片直传Azure Blob Storage咨询
问题核心原因
IBrowserFile.OpenReadStream()返回的BrowserFileStream仅支持异步读取操作,你代码中调用同步的Read()方法自然会触发「不支持同步读取」的报错- 把文件全量拷贝到
MemoryStream的实现方向完全错误,等于强制把几GB的文件全部加载到Blazor WASM的受限内存堆中,必然触发内存不足相关错误
正确实现方案
核心逻辑是每次仅异步读取当前分片大小的数据,处理完当前分片就释放对应内存,全程仅保留单个分片的内存占用,完全不需要加载整个文件到内存。你原来的逻辑只需要做两处修正:把同步读取改为异步读取、修正Read方法的偏移参数误用即可,修改后的代码如下:
@page "/" <InputFile OnChange="OnInputFileChange" /> @code{ async Task OnInputFileChange(InputFileChangeEventArgs e) { try { var file = e.File; // 建议调整为4MB,Azure块Blob最多支持50000个块,4MB分片最大支持195GB单文件,完全覆盖5GB需求 int blockSize = 4 * 1024 * 1024; int counter = 0; List<string> blockIds = new List<string>(); // 最大允许读取大小设置为5GB using var fs = file.OpenReadStream(5L * 1024 * 1024 * 1024); var bytesRemaining = fs.Length; do { var currentReadSize = (int)Math.Min(bytesRemaining, blockSize); byte[] blockBuffer = new byte[currentReadSize]; // 用异步读取,第二个参数是目标数组的写入偏移,不是流的读取偏移,填0即可,流会自动按顺序读取 var actuallyRead = await fs.ReadAsync(blockBuffer, 0, currentReadSize); bytesRemaining -= actuallyRead; if (actuallyRead > 0) { var blockId = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(counter.ToString("d6"))); Console.WriteLine($"blockId:{blockId}"); Console.WriteLine($"Block {counter:d6} 上传成功"); blockIds.Add(blockId); counter++; // 实际对接Azure时直接在这里调用StageBlockAsync提交当前分片即可,不需要保存分片数据 } } while (bytesRemaining > 0); Console.WriteLine("所有块上传完成,现在提交块列表"); // 实际对接Azure时在这里调用CommitBlockListAsync提交所有blockId即可 Console.WriteLine("Blob上传成功!"); } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
额外注意事项
- .NET 5的Blazor WASM对大文件流处理存在已知bug,建议至少升级到.NET 6 LTS版本,实测该版本及以上可以稳定支持5GB级别的分片上传
- 对接Azure Blob Storage时可以直接把读取到的
blockBuffer或者分片流传给Azure SDK的StageBlockAsync方法,不需要额外存储分片数据,进一步降低内存占用
内容的提问来源于stack exchange,提问作者INNVTV
相关产品推荐
相关产品推荐

