2015-12-30 30 views
3

我正在使用以下方法将目录的内容复制到其他目录。在C中复制大量数据的方法

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); 

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

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

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

    } 

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

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

我真的没有看到,我的理解特别好,这样清晰而简洁的任何帮助/资源将是巨大的任何解决方案。

感谢您的帮助!

+0

你可以使用一个单独的线程来运行,而不是在它的UI线程中运行它。 –

+0

你能量化一些你正在复制的东西吗?像目录,文件,传输的数据量一样,您可能会使用错误的工具进行作业 – konkked

+0

这是一个UI应用程序吗?如果是这样,请在后台线程中执行此操作。例如通过“Task.Run” –

回答

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

如果你的目标是从进入一个无响应的情况下停止的应用程序时,建议的方法使用缓冲区不会解决你的问题。相反,看看使用单独的Thread来复制你的目录。

更妙的是,使用BackgroundWorker,其具有能够报告进度的好处。

+0

是的,使用后台工作。您的应用程序将保持响应,您可以更新主进程中的变量以获取进度,并在完成时找出结果。 –

2

要快速解决您的问题。只有在这样的调用代码使用一个后台线程:

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

本例中使用,它使用线程池的一个线程来执行代码Task.Run method

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

1

假设,真正的问题是你的程序变得不响应...

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

典型的方法是简单地启动一个后台工作者,将复制工作交给它,然后让它去镇上,而你的gui线程响应用户输入。还有其他更复杂的技术也有更好的权衡,但我认为这将足以满足您所描述的情况。

(您Parallel.ForEach不会做的伎俩,因为触发它不会继续下去,直到Parallel.ForEach线程执行完)

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); 
     } 
    } 
} 
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(); 
      }); 

     }); 



    } 
相关问题