C#中使用SFTP下载文件时如何让ProgressBar进度条更新
修复SFTP下载进度条不更新的问题
问题根源
- 进度计算错误:原代码中
(double)totalBytesRead / fileLength得到的是0~1的小数比例,直接转int后始终为0(直到下载完成才会变成1),导致进度条毫无变化。 - UI线程阻塞风险:如果下载逻辑在UI线程执行,即使使用
Invoke更新进度,循环会持续占用UI线程,导致界面无法及时刷新。
修复后的完整代码
using (var client = new SftpClient(host, port, username, password)) { client.Connect(); // 获取远程文件属性与大小 var fileAttrs = client.GetAttributes(remoteFilePath); var fileLength = fileAttrs.Size; // 初始化进度条参数 progressBar1.Invoke((MethodInvoker)delegate { progressBar1.Maximum = 100; // 按百分比设置最大值 progressBar1.Minimum = 0; progressBar1.Value = 0; }); using (var fileStream = new FileStream(localFilePath, FileMode.Create)) { // 用using包裹SFTP流,确保自动释放资源 using (var sftpFileStream = client.OpenRead(remoteFilePath)) { var buffer = new byte[8192]; // 增大缓冲区提升下载效率 var totalBytesRead = 0L; int bytesRead; while ((bytesRead = sftpFileStream.Read(buffer, 0, buffer.Length)) > 0) { fileStream.Write(buffer, 0, bytesRead); totalBytesRead += bytesRead; // 计算百分比进度,避免超过最大值 var progressPercentage = (int)((double)totalBytesRead / fileLength * 100); progressPercentage = Math.Min(progressPercentage, 100); // 更新进度条并强制刷新UI progressBar1.Invoke((MethodInvoker)delegate { progressBar1.Value = progressPercentage; progressBar1.Refresh(); }); } } } client.Disconnect(); }
额外优化建议
- 移至后台线程:将下载逻辑放到
Task.Run中,避免阻塞UI线程,让界面保持响应:private void btnStartDownload_Click(object sender, EventArgs e) { Task.Run(() => { // 上述下载代码放在此处 }); } - 进度更新节流:可以添加判断,比如每下载1%或者间隔固定时间再更新进度条,减少
Invoke调用次数,降低UI负载。 - 合理设置缓冲区:根据网络情况调整缓冲区大小(如4096、8192),平衡下载效率与内存占用。
内容的提问来源于stack exchange,提问作者user15398536
相关产品推荐
相关产品推荐

