2015-12-30 31 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(); 
      }); 

     }); 



    } 
相關問題