2013-01-04 109 views
8

我正在編寫一個WPF應用程序在c#中,我需要移動一些文件 - 揉搓,我真的很需要知道,如果文件使它。要做到這一點,我寫了一張支票,使確保該文件獲取到移動後的目標目錄 - 問題是,有時我去檢查的文件移動完成之前:System.IO.File.Move - 如何等待移動完成?

System.IO.File.Move(file.FullName, endLocationWithFile); 

      System.IO.FileInfo[] filesInDirectory = endLocation.GetFiles(); 
      foreach (System.IO.FileInfo temp in filesInDirectory) 
      { 
       if (temp.Name == shortFileName) 
       { 

        return true; 
       } 
      } 

      // The file we sent over has not gotten to the correct directory....something went wrong! 
      throw new IOException("File did not reach destination"); 

     } 
     catch (Exception e) 
     { 
      //Something went wrong, return a fail; 
      logger.writeErrorLog(e); 
      return false; 
     } 

有人能告訴我如何確保文件實際到達目的地? - 我將移動的文件可能非常大 - (高達2小時的全高清MP4文件)

謝謝!

+2

如何管理通過複製流,而不是使用'Move'移動自己?你會知道到底發生了什麼。 – spender

+0

聽起來很棒....你能發佈一個關於如何做的更多信息的鏈接嗎? – Mizmor

+0

我添加了一個答案來幫助你。 – spender

回答

7

你可以使用流與AysncAwait以確保文件完全複製

像這樣的東西應該工作:

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    string sourceFile = @"\\HOMESERVER\Development Backup\Software\Microsoft\en_expression_studio_4_premium_x86_dvd_537029.iso"; 
    string destinationFile = "G:\\en_expression_studio_4_premium_x86_dvd_537029.iso"; 

    MoveFile(sourceFile, destinationFile); 
} 

private async void MoveFile(string sourceFile, string destinationFile) 
{ 
    try 
    { 
     using (FileStream sourceStream = File.Open(sourceFile, FileMode.Open)) 
     { 
      using (FileStream destinationStream = File.Create(destinationFile)) 
      { 
       await sourceStream.CopyToAsync(destinationStream); 
       if (MessageBox.Show("I made it in one piece :), would you like to delete me from the original file?", "Done", MessageBoxButton.YesNo) == MessageBoxResult.Yes) 
       { 
        sourceStream.Close(); 
        File.Delete(sourceFile); 
       } 
      } 
     } 
    } 
    catch (IOException ioex) 
    { 
     MessageBox.Show("An IOException occured during move, " + ioex.Message); 
    } 
    catch (Exception ex) 
    { 
     MessageBox.Show("An Exception occured during move, " + ex.Message); 
    } 
} 

如果您使用VS2010,你將必須安裝Async CTP使用新的異步/等待語法

+0

這是一個非常乾淨的解決方案 - 謝謝! – Mizmor

+0

爲什麼''使用''裏面的'if'。也就是說,爲什麼不'if(MessageBox.Show(...))File.Delete(sourceFile);'在兩個'使用'塊之外? (更好的是,包含一個'bool deleteSource = true'參數。) –

+0

爲什麼它很重要,兩者都會以同樣的方式工作,'using'內的'if'沒有任何區別,'using'語句只用於確保在流上調用dispose並且與if語句完全沒有關係,您可以使用100種方式編寫代碼並獲得相同的效果。 –

1

您可以觀察文件從原始目錄中消失,然後確認它們確實出現在目標目錄中。

我還沒有很好的文件觀察員的經驗。我可能會讓線程在等待AutoResetEvent等待一個單獨的線程或計時器運行,以定期檢查文件是否從原始位置消失,檢查它們是否位於新位置,或許(取決於您的環境和需求)執行文件的一致性檢查(例如MD5檢查)。一旦這些條件滿足,「檢查器」線程/定時器將觸發AutoResetEvent,以便原始線程可以進行。

在「檢查器」中包含一些「這是太長了」的邏輯。

0

您很可能希望移動發生在單獨的線程中,以便您不會在幾個小時內停止執行應用程序。

如果程序在移動未完成的情況下無法繼續,那麼您可以打開對話框並定期檢查移動線程以更新進度追蹤器。這爲用戶提供了反饋,並防止他們感覺程序已經被凍結。

有信息和示例在此位置: http://hintdesk.com/c-wpf-copy-files-with-progress-bar-by-copyfileex-api/

1

爲什麼不通過複製流管理自己的副本?

//http://www.dotnetthoughts.net/writing_file_with_non_cache_mode_in_c/ 
const FileOptions FILE_FLAG_NO_BUFFERING = (FileOptions) 0x20000000; 

//experiment with different buffer sizes for optimal speed 
var bufLength = 4096; 

using(var outFile = 
    new FileStream(
     destPath, 
     FileMode.Create, 
     FileAccess.Write, 
     FileShare.None, 
     bufLength, 
     FileOptions.WriteThrough | FILE_FLAG_NO_BUFFERING)) 
using(var inFile = File.OpenRead(srcPath)) 
{ 
    //either 
    //inFile.CopyTo(outFile); 

    //or 
    var fileSizeInBytes = inFile.Length; 
    var buf = new byte[bufLength]; 
    long totalCopied = 0L; 
    int amtRead; 
    while((amtRead = inFile.Read(buf,0,bufLength)) > 0) 
    { 
     outFile.Write(buf,0,amtRead); 
     totalCopied += amtRead; 
     double progressPct = 
      Convert.ToDouble(totalCopied) * 100d/fileSizeInBytes; 
     progressPct.Dump(); 
    } 
} 
//file is written 
0

嘗試定期在後臺任務中檢查copi ed文件 大小達到原始文件的文件大小(您可以在文件之間添加哈希比較)

0

最近遇到類似問題。

OnBackupStarts(); 
//.. do stuff 

new TaskFactory().StartNew(() => 
       { 
        OnBackupStarts() 
        //.. do stuff 
        OnBackupEnds(); 
       }); 


void OnBackupEnds() 
    { 
     if (BackupChanged != null) 
     { 
      BackupChanged(this, new BackupChangedEventArgs(BackupState.Done)); 
     } 
    } 

不要等待,反應事件