You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用BackgroundWorker下载文件时进度条不实时更新求助

问题:BackgroundWorker下载FTP文件时进度条不实时更新

我用BackgroundWorker从FTP服务器下载文件,但进度条仅在文件下载完成后才更新。下载过程中进度条停留在0状态并卡顿,下载完成后直接跳至100。以下是我的代码:

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(activeDownload.ftpPath);
    request.Credentials = new NetworkCredential(ftpUser, ftpPass);
    request.Method = WebRequestMethods.Ftp.DownloadFile;
    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    Stream responseStream = response.GetResponseStream();
    using (FileStream writer = new FileStream(activeDownload.localPath, FileMode.Create)) {
        long length = response.ContentLength;
        int bufferSize = 2048;
        int readCount;
        byte[] buffer = new byte[2048];
        long bytesread = 0;
        backgroundWorker1.ReportProgress(0);
        readCount = responseStream.Read(buffer, 0, bufferSize);
        while (readCount > 0) {
            bytesread += readCount;
            writer.Write(buffer, 0, readCount);
            backgroundWorker1.ReportProgress((int)(bytesread / activeDownload.fileSize) * 100);
            readCount = responseStream.Read(buffer, 0, bufferSize);
        }
    }
    response.Close();
    responseStream.Close();
}

private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
    progressBar1.Value = e.ProgressPercentage;
}

请问我哪里出现了错误?希望能得到各位的帮助。


问题分析与解决方案

嘿,我一眼就看到问题所在了——你在计算进度百分比的时候犯了一个整数除法的错误!

你看这句代码:

backgroundWorker1.ReportProgress((int)(bytesread / activeDownload.fileSize) * 100);

bytesread和activeDownload.fileSize都是长整型(long),当bytesread小于activeDownload.fileSize时,它们相除的结果是0(因为整数除法会直接舍弃小数部分),再乘以100还是0。只有当bytesread完全等于activeDownload.fileSize的时候,结果才会变成1*100=100,这就导致进度条一直卡在0,直到下载完成直接跳满。

另外还有个小细节:你已经用了using语句包裹FileStream来自动释放资源,但response和responseStream最好也用using来管理,这样能更安全地确保资源被正确释放,避免潜在的内存泄漏。

给你修正后的代码:

private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) {
    // 用sender获取当前的BackgroundWorker实例,比直接引用控件更灵活
    BackgroundWorker worker = sender as BackgroundWorker;
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(activeDownload.ftpPath);
    request.Credentials = new NetworkCredential(ftpUser, ftpPass);
    request.Method = WebRequestMethods.Ftp.DownloadFile;
    
    // 给response和responseStream加上using,自动管理资源
    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
    using (Stream responseStream = response.GetResponseStream())
    using (FileStream writer = new FileStream(activeDownload.localPath, FileMode.Create)) {
        long totalBytes = response.ContentLength;
        int bufferSize = 2048;
        byte[] buffer = new byte[bufferSize];
        long bytesRead = 0;
        int readCount;

        worker.ReportProgress(0);
        // 把readCount的赋值放到while条件里,代码更简洁
        while ((readCount = responseStream.Read(buffer, 0, bufferSize)) > 0) {
            bytesRead += readCount;
            writer.Write(buffer, 0, readCount);
            
            // 修正百分比计算:先乘以100再做除法,避免整数除法丢失精度
            int progress = (int)((bytesRead * 100) / totalBytes);
            worker.ReportProgress(progress);
        }
    }
}

private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) {
    progressBar1.Value = e.ProgressPercentage;
}

几个关键的修改点:

  • 把百分比计算逻辑从(bytesread / activeDownload.fileSize) * 100改成(bytesRead * 100) / totalBytes:先做乘法得到一个较大的数值,再做除法就能保留有效的百分比数值,避免了整数除法导致的精度丢失
  • 用sender获取当前的BackgroundWorker实例,而不是直接引用控件,这是更健壮的编程习惯
  • 给response和responseStream加上using语句,确保资源被正确释放
  • 优化了while循环的写法,把readCount的赋值放到条件里,让代码更简洁

这样修改后,进度条应该就能实时更新了,不会再卡顿在0啦!


内容的提问来源于stack exchange,提问作者Adam Stück

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:30:49