在C#中复制大量数据的方法

时间:2015-12-30 23:01:49

标签: c# directoryservices file-copying large-data

我使用以下方法将目录的内容复制到另一个目录。

} else {
         findComponent(str, c);
         return null;
}

我唯一的问题是源路径中有相当多的数据,并且在复制过程中程序没有响应。

我想知道我对复制数据的选择是什么。我做了一些研究,有人建议使用缓冲区。

我还没有真正看到任何我理解得特别好的解决方案,所以任何明确和简洁的帮助/资源都会很棒。

感谢您的帮助!

6 个答案:

答案 0 :(得分:3)

如果您的目标是阻止应用程序进入非响应状态,建议的使用缓冲区的方法将无法解决您的问题。相反,请查看使用单独的Thread复制目录。

更好的是,使用BackgroundWorker,这可以提供报告进度的额外好处。

答案 1 :(得分:2)

快速解决您的问题是在调用代码中使用后台线程,如下所示:

var source_directory = "c:\\source";
var destination_directory= "c:\\destination";
Task.Run(() => DirCopy(source_directory, destination_directory));

此示例使用Task.Run method使用其中一个线程池线程来执行代码。

这可以确保UI线程可以自由更新UI并响应用户输入。

答案 2 :(得分:2)

在Windows窗体中执行长任务,在消息线程上将导致表单无响应,直到任务完成。您将需要使用线程来防止这种情况发生。它可能会变得复杂,但您需要一个BackgroundWorker:

_Worker = new BackgroundWorker();
_Worker.WorkerReportsProgress = true;
_Worker.DoWork += Worker_DoWork;
_Worker.ProgressChanged += Worker_ProgressChanged;
_Worker.RunWorkerAsync();

预先形成任务的方法:

private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    worker.ReportProgress(1);

    // do stuff

    worker.ReportProgress(100);
}

报告进展的方法:

private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    switch (e.ProgressPercentage)
    {
        case 1:
            // make your status bar visible
            break;

        case 100:
            // hide it again
            break;
    }
}

您可以使用选取框进度条,但如果要报告实际百分比,则计算Worker_DoWork方法中的文件大小和进度可能会变得复杂,这是另一个问题。

https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx

答案 3 :(得分:2)

目前尚不清楚您正在使用的编译器/框架的版本,但您可以使用异步文件操作而不必担心线程。如果您有大型文件层次结构,也可以使用流版本EnumerateDirectoriesEnumerateFiles

public async Task DirCopy(string SourcePath, string DestinationPath)
{
    //slightly different from your code, in that the destination directory is simply removed recursively
    Directory.Delete(DestinationPath, true);

    //enumerate files returns earlier than get files for large file hierarchies
    //... because it is a streaming IEnumerable instead of an array
    foreach (var sourcePath in System.IO.Directory.EnumerateFiles(SourcePath, "*.*", SearchOption.AllDirectories))
    {
        var destinationPath = sourcePath.Replace(SourcePath, DestinationPath);

        //slightly different from your code, in that directories are created as needed
        //... however, this would mean empty directories are not copied
        Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));

        using (var source = File.Open(sourcePath, FileMode.Open, FileAccess.Read))
        using (var destination = File.Create(destinationPath))
        {
            //async copy of the file frees the current thread
            //... e.g. for the UI thread to process UI updates
            await source.CopyToAsync(destination);
        }
    }
}

答案 4 :(得分:1)

假设真正的问题是你的程序没有响应......

您的程序可能会停止响应,因为您用于执行副本的线程是您用来响应用户输入的线程。如果希望在程序保持响应的同时在后台继续复制,则必须异步执行复制。 (我假设您根据上下文使用winforms或wpf。)

典型的方法是简单地启动后台工作人员,将复制作业发送给它,然后让你的gui线程响应用户输入时进入城镇。还有其他更复杂的技术也有更好的权衡,但我怀疑这对于你所描述的情况就足够了。

(你的$ bash a.sh hello hello <-- it expands when unquoted double quotes hello $r <-- it does not expand with "EOL" single quotes hello $r <-- it does not expand with 'EOL' 没有做到这一点,因为触发它的线程在Parallel.ForEach完成执行之前不会继续)

答案 5 :(得分:0)

谢谢大家,我非常感谢所有输入,以了解实现这一目标的不同方法。暂时我决定只做一个Task.Run,​​但我会调查后台工作者和异步操作。

再次感谢大家!

作为参考,我刚刚做了

Task.Run(()=>{ DirCopy("source","destination"); });

DirCopy

public void DirCopy(string SourcePath, string DestinationPath)
    {
        if (Directory.Exists(DestinationPath))
        {
            System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(DestinationPath);

            foreach (FileInfo file in downloadedMessageInfo.GetFiles())
            {
                file.Delete();
            }
            foreach (DirectoryInfo dir in downloadedMessageInfo.GetDirectories())
            {
                dir.Delete(true);
            }
        }



        //=================================================================================
        string[] directories = System.IO.Directory.GetDirectories(SourcePath, "*.*", SearchOption.AllDirectories);
        string[] files = System.IO.Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories);

        totalPB.Minimum = 0;
        totalPB.Maximum = directories.Length;
        totalPB.Value = 0;
        totalPB.Step = 1;

        subTotalPB.Minimum = 0;
        subTotalPB.Maximum = directories.Length;
        subTotalPB.Value = 0;
        subTotalPB.Step = 1;

        Parallel.ForEach(directories, dirPath =>
        {
            Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath));
            subTotalPB.PerformStep();
        });

        Task.Run(() => 
        {

            Parallel.ForEach(files, newPath =>
            {
                File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true);
                totalPB.PerformStep();
            });

        });



    }