【问题标题】:WPF Showing progress bar during async file copyWPF 在异步文件复制期间显示进度条
【发布时间】:2016-02-17 00:58:46
【问题描述】:

我是 wpf 新手,所以这个问题可能是微不足道的。 我正在尝试将文件从一个文件夹复制到另一个文件夹。我想在复制过程中显示一个进度条。

我的代码是这样的:

if (!System.IO.File.Exists(basemapDest))
{
    await Copier.CopyFiles(new Dictionary<string, string>
    {
        {basemapSrc, basemapDest},
    }, prog => prgBaseMap.Value = prog);
}

public static class Copier
{
    public static async Task CopyFiles(Dictionary<string, string> files, Action<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))
                {
                    long fileLength = from.Length;
                    await inStream.CopyToAsync(outStream);
                }
            }

            progressCallback((int)((x + 1) / files.Count) * 100);
        }
    }
}

我的 XAML 代码:

<StackPanel>
    <ProgressBar x:Name="prgBaseMap" Height="10" Visibility="Collapsed"/>
</StackPanel>

虽然这适用于报告文件已复制,但在我进行复制时不会显示进度。我做错了什么?

*** 编辑,这不是stream.copyto with progress bar reporting的副本

引用的问题是使用 BackgroundWorker,如今许多人认为它已过时。这个问题是关于使用 .NET 的新异步模型。我希望提供的解决方案对其他人也有用。

【问题讨论】:

  • 什么是prgBaseMap?你想念那个类的INotifyPropertyChanged 实现吗?
  • 您希望显示什么样的进度?您发布的代码将在复制每个文件后更新进度。您只是在复制一个文件,所以我不希望在屏幕上看到任何有用的进度显示。如果您希望在复制文件时 更新进度,则必须使用更明确的方式进行复制,并在读取文件的较小块并将其写入新文件时更新进度.
  • 很遗憾,您的要求不是很清楚。请提供可靠地重现问题的a good, minimal, complete code example,并准确描述该代码的作用以及与您希望它做的不同之处。
  • PeterDuniho,@torvin,你们都是正确的,也许我的问题不是最详细的。我想显示的进度是在复制文件时,在这部分代码中:await nStream.CopyToAsync(outStream);我已经添加了我的 prgBaseMap 的 Xaml 声明基本上,我想显示一个进度指示器,因为正在下载一个文件,估计完成了多少时间等

标签: c# wpf xaml


【解决方案1】:

这是一个允许您在复制文件时显示进度的解决方案:

public static class Copier
{
    public static async Task CopyFiles(Dictionary<string, string> files, Action<double> progressCallback)
    {
        long total_size = files.Keys.Select(x => new FileInfo(x).Length).Sum();

        long total_read = 0;

        double progress_size = 10000.0;

        foreach(var item in files)
        {
            long total_read_for_file = 0;

            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 CopyStream(inStream , outStream, x =>
                    {
                        total_read_for_file = x;
                        progressCallback(((total_read + total_read_for_file)/ (double)total_size) * progress_size);
                    } );
                }
            }

            total_read += total_read_for_file;
        }
    }

    public static async Task CopyStream(Stream from, Stream to, Action<long> progress)
    {
        int buffer_size = 10240;

        byte[] buffer = new byte[buffer_size];

        long total_read = 0;

        while (total_read < from.Length)
        {
            int read = await from.ReadAsync(buffer, 0, buffer_size);

            await to.WriteAsync(buffer, 0, read);

            total_read += read;

            progress(total_read);
        }
    }

}

你可以这样使用它:

var dictionary = new Dictionary<string, string>
{
    {"c:\\source_file1.dat", "c:\\destination_file1.dat"},
    {"c:\\source_file2.dat", "c:\\destination_file2.dat"},
};

prgBaseMap.Maximum = 10000.0;

await Copier.CopyFiles(dictionary, prog => prgBaseMap.Value = prog);

此解决方案通过一次手动复制文件内容 10k 字节来工作(CopyStream 方法)。并且每次更新进度条。

在开始时,它将源文件的总长度相加,以便能够计算相对进度。

CopyFiles 方法将通过以相对于10000.0 的进度回调来向调用者报告进度。这就是为什么进度条的最大值需要达到 10000.0。

您可以使用输入文件长度的总和,而不是使用双精度值 10000.0。这使您还可以报告复制的字节总数。

在这种情况下,您必须计算调用方的长度总和。

【讨论】:

  • 谢谢,这很有魅力。我只是期待一个指针或提示,一个具有出色解释的完全有效的解决方案真的让我很开心。谢谢,我希望这对将来对异步复制文件感兴趣的其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 2012-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多