繁体   English   中英

WPF在异步文件复制过程中显示进度栏

[英]WPF Showing progress bar during async file copy

我是wpf newb,所以这个问题可能很简单。 我正在尝试将文件从一个文件夹复制到另一个文件夹。 我想在复制过程中显示进度条。

我的代码是这样的:

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的副本

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

这是一个解决方案,可让您在复制文件时显示进度:

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的双10000.0值。 这样,您还可以报告已复制字节的总数。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM