2009-07-20 70 views
12

我正在監視文件夾中的新文件並需要處理它們。問題是偶爾文件打開會失敗,因爲系統還沒有完成複製。如何測試一個文件是否以.NET完全複製

什麼是測試文件是否完成複製的正確方法?

澄清: 我沒有對文件夾/文件的寫入權限,也無法控制複製過程(它是用戶)。

+0

好問題!當我遇到這個問題時,我只是添加了System.Threading.Thread.Sleep(1000),但我會*愛*以獲得更好的解決方案(這真是太蹩腳......) – Treb 2009-07-20 07:38:57

+0

您是否有讀取原始文件的權限,哪些被複制? – 2009-07-20 07:54:30

回答

11

我認爲唯一可行的方法是嘗試單獨打開文件並捕獲特定異常。我通常討厭使用普通的應用程序邏輯的例外,但恐怕對於這種情況有沒有其他的方法(至少我還沒有找到一個尚未):

public bool FileIsDone(string path) 
{ 
    try 
    { 
    using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None)) 
    { 
    } 
    } 
    catch(UnauthorizedAccessException) 
    { 
    return false; 
    } 

    return true; 
} 
0

我總是採取的一種方法是在我的複製/傳輸結束時創建一個名爲「token.txt」而沒有內容的文件。這個想法是,這個文件將在傳輸操作結束時被創建,所以你可以監視這個文件的創建,當這個文件被創建時,你開始使用你的文件。當你開始處理你的文件時,不要忘記擦除這個令牌文件。

0

你也應該包括類似情況:文件正在使用由其他程序,文件已被刪除(副本沒成功)等等。

使用擴展的異常處理覆蓋可能發生的所有重要案例。

2

不確定「正確的方式」,但您可以使用監測工具(我猜想可以使用FileSystemWatcher)來填充用於延遲處理的內部隊列。或者更好的方法是:使用隊列將文件置於打開失敗的文件中,以便稍後重試。

1

如果您使用FileSystemWatcher我不認爲這個問題有一個可靠的解決方案。一種方法是稍後嘗試/捕獲/重試。

0

這取決於,如果您無法控制複製過程,則重試循環可能是最好的。

如果你有控制:

  • 如果文件夾是本地的,你可以要求人們寫的東西把它鎖獨佔訪問該文件,只有當他們完成解除鎖定(這我認爲是File.Copy的默認值)。在.Net方面,你可以有一個簡單的重試循環,一個冷靜期。
    • 或者,您可以將文件寫入臨時文件夾,並且只有在寫入後纔將其移至目標目錄。這減少了可能發生不良事情的窗口(但不會消除它)
  • 如果文件夾是SMB共享,​​則有可能LockFile甚至不能工作(某些linux實現)。在這種情況下,常見的方法是創建一種鎖文件,一旦創建文件的人完成,該文件就會被刪除。鎖文件方法的問題是,如果你忘記刪除它,你可能會遇到麻煩。
  • 在這些複雜情況下,我會建議通過WCF服務或Web服務接收數據可能是有利的,因爲你有更好的控制。
0

事實上,爲了避免競爭條件下,只有安全的解決方案是重試。

如果你做這樣的事情:

while (file is locked) 
    no-op() 
process file() 

你可能另一個進程的同時,防範和工藝文件中的語句之間的走馬觀花。無論您如何實施「等待文件可用性」,除非您可以確保解鎖後您是第一個訪問它的進程,否則您可能是而不是是第一個用戶。

這很可能是乍一看,特別是如果多人在觀看該文件,特別是如果他們使用類似文件系統觀察者的東西的話。當然,它仍然不是特別有可能...

0

這些文件很大嗎?

也許你可以嘗試計算文件上的MD5校驗和?

如果您將md5哈希置於文件名中,您可以檢索它並嘗試重新計算文件上的校驗和。當md5匹配時,您可以假定文件已完成。

byte[] md5Hash = null; 
MD5 md5 = new MD5CryptoServiceProvider(); 
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) 
    md5Hash = md5.ComputeHash(fs); 

StringBuilder hex = new StringBuilder(); 
foreach (byte b in md5Hash) 
    hex.Append(b.ToString("x2")); 
0

這是我使用的vb.net循環。 每次檢查之間等待2秒鐘。

Dim donotcopy As Boolean = True 
While donotcopy = True 
    Dim myFile As New FileInfo("Filetocopy") 
    Dim sizeInBytes As Long = myFile.Length 
    Thread.Sleep(2000) 
    Dim myFile2 As New FileInfo("Filetocopy") 
    Dim sizeInBytes2 As Long = myFile2.Length 
    If sizeInBytes2 = sizeInBytes Then donotcopy = False 
End While 
相關問題