【问题标题】:C# Asynchronous File Copy with Progress Bar带有进度条的 C# 异步文件复制
【发布时间】:2021-07-09 09:27:55
【问题描述】:

我正在尝试编写一个 C# 应用程序,在复制多个文件时更新进度条。我正在使用这种方法进行复制,需要 Dictionary<string, string>:

public static async Task CopyFiles(Dictionary<string, string> files, IProgress<int> progressCallback)
{
    for (var x = 0; x < files.Count; x++)
    {
        var item = files.ElementAt(x);
        var from = item.Key;
        var to = item.Value;

        using (var outStream = new FileStream(to, FileMode.Create, FileAccess.Write, FileShare.Read))
        {
            using (var inStream = new FileStream(from, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                await inStream.CopyToAsync(outStream);
            }
        }

        var percentComplete = ((x + 1) / files.Count) * 100;
        //progressCallback((int)((x + 1) / files.Count) * 100);
        progressCallback.Report(percentComplete);
    }
}

在我的主类中,我正在使用以下代码尝试更新我的进度条 (progressBar1),但此代码似乎无法正常工作,似乎在复制两个文件和结束时完成了 ProgressBar大约需要一秒钟才能完成,不知道为什么会这样。

private async void button4_Click(object sender, EventArgs e) 
{
        button4.Enabled = false;

        var progress = new Progress<int>(percent =>
        {
            progressBar1.Value = percent;
        });

        await Copier.CopyFiles(new Dictionary<string, string> {
            { Source1, Destination1 },
            { Source2, Destination2 }
        },
            progress);

        button4.Enabled = true;
        MessageBox.Show("Completed");
    }
}

【问题讨论】:

  • 考虑使用调度程序异步调用progressCallback(在 UI 线程中运行回调)。至于不起作用,预期的行为是什么?需要超过一秒钟吗?如果把CopyToAsync换成Task.Delay,问题还在吗?
  • 使用 var percentComplete = (((x + 1) * 100) / 2) ****** 当使用 ((x + 1) / files.Count) * 100 结果为零。
  • @Sinatr 这就是进度条所做的。它没有任何问题。它实际上比硬编码对 UI 或更糟糕的特定控件的调用更可取。另一方面,整数除法可能很有趣
  • 整数除法保证小于files.Count的值将为0,此时结果将为1。但没有理由在异步方法中计算百分比。您可以指定进度条的当前值和最大值,并仅报告x。您可以报告复杂的对象,而不仅仅是原始类型

标签: c# .net wpf


【解决方案1】:

问题是因为整数除法x + 1 / files.Count 为除最后一个之外的每个x 返回零。您可以通过先乘以 100 (100*(x+1)/files.Count) 来解决此问题,但还有更好的选择。

无需在CopyFiles 中计算和报告百分比。您可以设置进度条的最大值:

    private async void button4_Click(object sender, EventArgs e) 
    {
            button4.Enabled = false;

            var files = new Dictionary<string, string> {
                { Source1, Destination1 },
                { Source2, Destination2 }
            };
            
            progressBar1.Maximum=files.Count;
            progressBar1.Value =0;
            var progress = new Progress<int>(x =>
            {
                progressBar1.Value = x+1;
            });

            await Copier.CopyFiles(files,progress);

            button4.Enabled = true;
            MessageBox.Show("Completed");
        }
    }

并且只报告当前的迭代:

    public static async Task CopyFiles(Dictionary<string, string> files, IProgress<int> progressCallback)
    {
        for (var x = 0; x < files.Count; x++)
        {
            
            ...
            progressCallback.Report(x);
        }
    }

IProgress&lt; T&gt; 可以处理复杂的对象,而不仅仅是原始类型。可以报​​告迭代和文件名以显示在状态栏中:

record CopyProgress(int Iteration, string From, string To);
...

var progress = new Progress<int>(x =>
        {
            progressBar1.Value = x.Iteration;
            statusText.Text = $"Copied {x.From} to {x.To}";
        });

...
progressCallback.Report(new CopyProgress(x,from,to);

【讨论】:

  • dict.Count -- 表示files.Count?对吗?
  • 感谢您的回答,不幸的是,该解决方案似乎不起作用,它仍在做同样的事情。该按钮禁用,它开始在后台复制,然后在完成前一秒钟,进度条快速完成,然后显示带有“已完成”的消息框
猜你喜欢
  • 1970-01-01
  • 2011-08-28
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多