Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步复制大文件,同时向进度条报告进度(示例?)_C#_Multithreading_Asynchronous_System.io.file - Fatal编程技术网

C# 异步复制大文件,同时向进度条报告进度(示例?)

C# 异步复制大文件,同时向进度条报告进度(示例?),c#,multithreading,asynchronous,system.io.file,C#,Multithreading,Asynchronous,System.io.file,我需要复制一些大文件,并通过进度条将进度报告回UI 我买了“C#5.0简而言之”。我在597页。我一直在读关于并行编程的书。根据本书中的一些例子,我试图完成我心目中非常简单的事情,但我真的很挣扎。我的理解一定有差距。这就是我发布这个问题的原因 我已经调查了后台工作人员,但当我试图取得进展时,发现自己遇到了跨线程编译器错误 我研究过异步命令,但发现自己误解了lambda表达式。或者如何通过单击按钮异步执行任务代码,同时仍向UI线程报告进度 我已经在MSDN、codeproject上详细介绍了许多现

我需要复制一些大文件,并通过进度条将进度报告回UI

我买了“C#5.0简而言之”。我在597页。我一直在读关于并行编程的书。根据本书中的一些例子,我试图完成我心目中非常简单的事情,但我真的很挣扎。我的理解一定有差距。这就是我发布这个问题的原因

我已经调查了后台工作人员,但当我试图取得进展时,发现自己遇到了跨线程编译器错误

我研究过异步命令,但发现自己误解了lambda表达式。或者如何通过单击按钮异步执行任务代码,同时仍向UI线程报告进度

我已经在MSDN、codeproject上详细介绍了许多现有的问题/答案,我自己也在这里问了一些问题,并将其否决。我只需要一个简单的例子,我可以绞尽脑汁,我会在我的道路上

我相信我的答案是async、Task.Run、File.Copy(可能是StreamReader/StreamWriter类)和IProgress。我在两周的研究和反复试验中发现的问题/答案要么不完整,要么对于某些特定场景来说过于宽泛/过于具体

我只需要一个带有进度条的UI的工作示例,以及一个在新线程中执行代码以复制一组大文件(或仅一个大文件)并报告进度的按钮。从那里,我可以玩它,并调整它,以我的需要,并进一步我的整体理解

代码改编自Clint的答案,但仍无法正确更新进度

此自适应在异步任务中复制文件,但仅在复制文件后才将进度从0%更新到100%。因为我处理的是大文件,基于文件数量的处理进度是不够的

到目前为止,我还没有发现或尝试过在更新大文件的逐字节进度时异步执行复制的地址

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.IO;

namespace CopyProgressWorking
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            string srcFile = @"C:\temp\BigFile.txt";
            string dstFile = @"C:\temp\temp2\BigFile.txt";
            button1.Click += (s, e) => DoCopy(srcFile, dstFile);
        }

        public 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 size = inStream.Position;
                        Console.WriteLine("Filesize is {0}", size);
                        await inStream.CopyToAsync(outStream);

                    }
                }

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

        public async void DoCopy(string srcFile, string dstFile)
        {
            label1.Text = "Copying " + srcFile;
            await CopyFiles(new Dictionary<string, string>
            {
                {srcFile, dstFile}
            },
            prog =>
            {
                Invoke((MethodInvoker)delegate {
                    progressBar1.Value = prog;
                    if (prog >= 100)
                    {
                        label1.Text = "Copy complete!";
                    }
                });
            });
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
使用System.Threading.Tasks;
使用System.IO;
命名空间CopyProgressWorking
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
字符串srcFile=@“C:\temp\BigFile.txt”;
字符串dstFile=@“C:\temp\temp2\BigFile.txt”;
按钮1.点击+=(s,e)=>DoCopy(srcFile,dstFile);
}
公共异步任务复制文件(字典文件、操作进程回调)
{
对于(var x=0;x
{
调用((MethodInvoker)委托{
progressBar1.Value=prog;
如果(程序>=100)
{
标签1.Text=“复制完成!”;
}
});
});
}
}
}

这应该让您开始:

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))
                {
                    await inStream.CopyToAsync(outStream);
                }
            }

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

public class MyUI
{
    public MyUI()
    {
        copyButton.Click += (s,e) => DoCopy();
    }

    public async void DoCopy()
    {
        await Copier.CopyFiles(new Dictionary<string,string>
        {
            {"C:\file1.txt", "C:\users\myuser\desktop\file1.txt"},
            {"C:\file2.txt", "C:\users\myuser\desktop\file2.txt"}
        }, prog => MyProgressBar.Value = prog);
    }
}
公共静态类复印机
{
公共静态异步任务复制文件(字典文件、操作进程回调)
{
对于(var x=0;xDoCopy();
}
公共异步void DoCopy()
{
等待Copier.CopyFiles(新字典
{
{“C:\file1.txt”,“C:\users\myuser\desktop\file1.txt”},
{“C:\file2.txt”,“C:\users\myuser\desktop\file2.txt”}
},prog=>MyProgressBar.Value=prog);
}
}
这是在没有visual studio的情况下手工编写的,因此可能存在一些问题(拼写等)

核心概念是:

  • 用于异步编程
  • 使用匿名方法(lambda)回调来报告方法外的进度
  • 基本上,该代码所做的全部工作是:

  • 使用字典表示要复制的文件位置(当前和新)
  • 遍历其中的每一个,并使用文件流和异步复制功能执行复制
  • 通过回调报告总体进度
  • 示例类“MyUI”只是winforms或WPF窗口的一个非常精简的版本,带有一个按钮(在click事件处理程序中)启动它
    // Assuming you've got a from and to file stream open
    // here is some hand-written pseudocode (C# style) to show the basic concept
    foreach(var file in files)
    {
        var from = OpenFromStream(file.From);
        var to = OpenFromStream(file.To);
    
        var lengthOfFile = from.Length;
        for(x = 0; x < lengthOfFile; x++)
        {
            to.WriteByte(from.ReadByte());
            progress((int)(x / lengthOfFile) * 100);
        }
    }