在一直项目中使用文件下载,同事反应下载文件做进度条的时候没有正常显示进度条 大致代码如下
public class DowmloadModel { public string Url { get; set; } public string LocalSaveFullPath { get; set; } public bool Iscontinue { get; set; } public Action<double> ProgressRollBack { get; set; } public CancellationToken CancellationToken { get; set; } } public class DownloadHelper { public static async Task DowmloadResumeFilel(DowmloadModel dowmloadModel) { try { //不建议使用WebResponse,所以这里用了未被淘汰的HttpClient var client = new HttpClient(); //默认是下载新文件 long downloaded = 0; if (dowmloadModel.Iscontinue) { if (File.Exists(dowmloadModel.LocalSaveFullPath)) { // 如果是续传,获取已经下载了多少 downloaded = new FileInfo(dowmloadModel.LocalSaveFullPath).Length; } } else { //不是续传,重新下载的就把原来的删了 File.Delete(dowmloadModel.LocalSaveFullPath); } var request = new HttpRequestMessage(HttpMethod.Get, dowmloadModel.Url); //从指定位置开始下载文件,这样子写法兼容断点续传 request.Headers.Range = new RangeHeaderValue(downloaded, null); using (var response = await client.SendAsync(request)) { //检查请求是否成功,官方语法糖封装 response.EnsureSuccessStatusCode(); //记录总下载量 var totalLength = response.Content.Headers.ContentRange.Length; using var stream = await response.Content.ReadAsStreamAsync(); //启用文件追加模式,确保之前下载一半的文件还能被续上 using var fileStream = new FileStream(dowmloadModel.LocalSaveFullPath, FileMode.Append, FileAccess.Write); //传输层的优化buffer大小一般在4KB左右,选择4KB可以与传输层匹配,减少 copying数据的次数, 提高效率 var buffer = new byte[4096]; int read = 0; //缓存已下载的字节数量,到达一个阈值再通知界面变更 var temp = 0; while ((read = await stream.ReadAsync(buffer)) > 0) { //如果外部取消了就不继续下载了 dowmloadModel.CancellationToken.ThrowIfCancellationRequested(); //将字节数追加写入文件 await fileStream.WriteAsync(buffer.AsMemory(0, read)); downloaded += read; temp += read; //以百分之一进度为阈值更新界面 if (temp > totalLength / 100) { dowmloadModel.ProgressRollBack((double)((double)downloaded / totalLength) * 100); temp = 0; } } } } catch (Exception ex) { //Log.Error($"下载出错:{ex}"); } } }
UI显示部分
await DownloadResumeFile(new DownloadModel() { Url = dataContext.ApkFilePath, Iscontinue = false, LocalSaveFullPath = Path.Combine(Path.GetTempPath(), $"{dataContext.AppName}.apk"), ProgressRollBack = rusult => { dataContext.DownloadProgress = rusult; }, CancellationToken = dataContext.DownloadingCancellationToken.Token, });
分析之后定位在
using (var response = await client.SendAsync(request)) 和 dataContext.DownloadProgress = rusult;
最后修改为 using (var response = await client.SendAsync(request,HttpCompletionOption.ResponseHeadersRead))
Application.Current.Dispatcher.Invoke(() =>
{
dataContext.DownloadProgress = rusult;
});
修复正常。做下记录。
标签:文件,await,dowmloadModel,var,new,public,下载,httpClient From: https://www.cnblogs.com/stweily/p/18612731