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

异步FTP文件下载及进度条显示的技术实现问题

解决FTP下载进度条跨线程更新问题

看起来你现在的代码存在UI线程跨线程访问的风险——直接在Task.Run的后台线程里操作pBar这个UI控件,会触发InvalidOperationException,因为WPF/WinForms的UI控件只能在创建它们的线程(也就是UI线程)上修改。

我给你调整一下代码,用.NET推荐的IProgress<T>接口来安全更新进度条,既简洁又符合最佳实践:

第一步:修改自定义FtpClient的DownloadFile方法

不要直接传递ProgressBar控件,而是接收IProgress<int>来报告进度百分比:

public string DownloadFile(string source, string destination, IProgress<int> progress)
{
    // 初始化FTP请求(替换成你自己的FTP连接逻辑)
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create($"ftp://your-ftp-server/{source}");
    request.Method = WebRequestMethods.Ftp.DownloadFile;
    // 添加FTP认证信息,比如 request.Credentials = new NetworkCredential("用户名", "密码");

    using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
    using (Stream responseStream = response.GetResponseStream())
    using (FileStream fileStream = new FileStream(destination, FileMode.Create))
    {
        long totalFileSize = response.ContentLength;
        long downloadedBytes = 0;
        byte[] buffer = new byte[4096]; // 4KB分块下载,可根据需求调整大小
        int bytesRead;

        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
        {
            fileStream.Write(buffer, 0, bytesRead);
            downloadedBytes += bytesRead;

            // 计算当前进度百分比并报告
            int progressPercent = (int)((downloadedBytes * 100) / totalFileSize);
            progress?.Report(progressPercent);
        }

        return $"Done: {Path.GetFileName(source)} 下载完成";
    }
}

第二步:修改调用逻辑,安全更新UI

在UI线程创建Progress<int>对象,它会自动在UI线程处理进度更新,不用手动写Dispatcher:

SaveFileDialog sfd = new SaveFileDialog();
if (sfd.ShowDialog() == true)
{
    pBar.Visibility = Visibility.Visible;
    pBar.Minimum = 0;
    pBar.Maximum = 100;
    pBar.Value = 0; // 重置进度条初始状态

    string filename = entry.FileName.Text;

    // 创建进度回调,自动在UI线程执行更新
    var downloadProgress = new Progress<int>(percent =>
    {
        pBar.Value = percent;
    });

    // 后台执行下载任务,不阻塞UI
    string status = await Task.Run(() =>
    {
        return client.DownloadFile(filename, sfd.FileName, downloadProgress);
    });

    statusBox.Text = status.Substring(4);
}

关键要点解释

  • 避免直接操作UI控件:后台线程永远不要直接修改UI元素,IProgress<T>是.NET官方推荐的跨线程UI更新方案,内部已经封装了Dispatcher的调用逻辑,不用自己写繁琐的线程切换代码。
  • 分块下载+进度计算:用固定大小的缓冲区分块读取文件,实时计算已下载字节占总大小的比例,保证进度条平滑更新,不会出现跳变。
  • 异步等待:用await Task.Run()避免阻塞UI线程,让界面在下载过程中保持可响应状态,不会出现假死。

内容的提问来源于stack exchange,提问作者IAmVisco

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:35:16