Xamarin Forms中用Azure.Storage.Blobs V12实现分片上传与进度跟踪
Xamarin Forms + Azure.Storage.Blobs V12 分片上传与进度跟踪实现方案
一、分片上传实现(AzureDataLakeManager.cs 修改)
Azure Blob Storage V12 中,分片上传通过 BlockBlobClient 实现,核心流程是分块上传文件数据,最后提交块列表完成合并。以下是修改后的上传逻辑:
using Azure.Storage.Blobs; using Azure.Storage.Blobs.Specialized; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; public class AzureDataLakeManager { private readonly BlobServiceClient _blobServiceClient; private const int ChunkSize = 8 * 1024 * 1024; // 8MB 块大小,可根据需求调整(推荐4MB-100MB) public AzureDataLakeManager(string connectionString) { _blobServiceClient = new BlobServiceClient(connectionString); } /// <summary> /// 分片上传文件,并支持进度回调 /// </summary> /// <param name="filePath">本地文件路径</param> /// <param name="containerName">ADLS容器名</param> /// <param name="blobName">目标Blob名称</param> /// <param name="progress">进度回调(已上传字节数)</param> /// <param name="cancellationToken">取消令牌</param> public async Task UploadFileInChunksAsync(string filePath, string containerName, string blobName, IProgress<long> progress, CancellationToken cancellationToken = default) { var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); await containerClient.CreateIfNotExistsAsync(cancellationToken: cancellationToken); var blockBlobClient = containerClient.GetBlockBlobClient(blobName); var blockIds = new List<string>(); long totalBytesUploaded = 0; using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[ChunkSize]; int bytesRead; int blockIndex = 0; while ((bytesRead = await fileStream.ReadAsync(buffer, 0, ChunkSize, cancellationToken)) > 0) { // 生成唯一块ID(必须Base64编码) string blockId = System.Convert.ToBase64String(System.BitConverter.GetBytes(blockIndex)); blockIds.Add(blockId); // 上传当前块 using (var chunkStream = new MemoryStream(buffer, 0, bytesRead)) { await blockBlobClient.StageBlockAsync(blockId, chunkStream, cancellationToken: cancellationToken); } // 更新已上传字节数并触发进度回调 totalBytesUploaded += bytesRead; progress?.Report(totalBytesUploaded); blockIndex++; cancellationToken.ThrowIfCancellationRequested(); } // 提交所有块,完成文件合并 await blockBlobClient.CommitBlockListAsync(blockIds, cancellationToken: cancellationToken); } } }
二、进度跟踪与ProgressBar联动(MyStudio.Xaml + MyStudio.Xaml.cs)
1. XAML布局(MyStudio.Xaml)
确保布局中包含ProgressBar及相关控件:
<StackLayout Margin="20"> <Button x:Name="UploadBtn" Text="开始上传" Clicked="UploadBtn_Clicked"/> <ProgressBar x:Name="UploadProgressBar" Progress="0" HeightRequest="20" Margin="0,10,0,0"/> <Label x:Name="ProgressLabel" Text="0%" Margin="0,5,0,0"/> </StackLayout>
2. 代码逻辑(MyStudio.Xaml.cs)
通过 IProgress<long> 接收上传进度,在UI线程更新ProgressBar和进度文本:
using Xamarin.Forms; using System; using System.IO; public partial class MyStudio : ContentPage { private readonly AzureDataLakeManager _adlsManager; private long _totalFileSize; // 上传文件总大小 public MyStudio() { InitializeComponent(); // 替换为你的ADLS连接字符串 _adlsManager = new AzureDataLakeManager("your-adls-connection-string"); } private async void UploadBtn_Clicked(object sender, EventArgs e) { UploadBtn.IsEnabled = false; UploadProgressBar.Progress = 0; ProgressLabel.Text = "0%"; // 替换为你的本地文件路径、容器名、Blob名 string filePath = "/path/to/your/local/file"; string containerName = "your-container"; string blobName = "target-file-name.ext"; // 获取文件总大小 var fileInfo = new FileInfo(filePath); _totalFileSize = fileInfo.Length; // 定义进度回调,确保在UI线程更新控件 var progress = new Progress<long>(bytesUploaded => { Device.BeginInvokeOnMainThread(() => { double progressValue = (double)bytesUploaded / _totalFileSize; UploadProgressBar.Progress = progressValue; ProgressLabel.Text = $"{Math.Round(progressValue * 100)}%"; }); }); try { await _adlsManager.UploadFileInChunksAsync(filePath, containerName, blobName, progress); await DisplayAlert("成功", "文件上传完成", "确定"); } catch (Exception ex) { await DisplayAlert("错误", $"上传失败:{ex.Message}", "确定"); } finally { UploadBtn.IsEnabled = true; } } }
关键注意事项
- 块大小:推荐设置为4MB到100MB之间,过小会增加API调用次数,过大可能导致单块上传超时。
- 块ID:必须是Base64编码的唯一值,且长度不能超过64字节。
- UI线程更新:Xamarin Forms中所有UI操作必须在主线程执行,因此用
Device.BeginInvokeOnMainThread包裹进度更新逻辑。 - 异常处理:可根据需求添加块上传重试逻辑,避免网络波动导致的上传失败。
内容的提问来源于stack exchange,提问作者hk77
相关产品推荐
相关产品推荐

