2013-11-09 46 views
6

我打開一個文件進行讀取,我已經在用戶的%TEMP%文件夾中以前創建,使用下面的代碼:可以使用FileShare.Delete導致UnauthorizedAccessException?

new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete); 

在一些用戶的計算機上,這有時會拋出消息「的UnauthorizedAccessException訪問路徑...被拒絕「。我一直無法重現這一點。我最初的猜測是反病毒或索引引擎做了一些奇怪的事情,但我也注意到這段代碼使用了「FileShare.Delete」,我不知道應該在那裏。

是否有使用「FileShare.Delete」導致UnauthorizedAccessException的情況?

回答

12

是的,FileShare.Delete往往會導致此問題。任何在後臺運行並掃描文件的程序都會使用它們,文件索引器和病毒掃描程序就是常見的例子。

FileShare.Delete允許另一個進程刪除文件,即使後臺進程仍然打開文件並正在從中讀取文件。其他進程將不知道該文件實際上並沒有消失,因爲它知道該文件實際上已被刪除。

當其他進程依賴於文件實際被刪除並執行其他操作時,麻煩就開始了。通常通過創建一個具有相同名稱的新文件來觸發。值得注意的是一種非常不明智的方式來保存文件,因爲當保存失敗時會導致完整的數據丟失而無需備份,但是這種錯誤非常普遍。

這將失敗,因爲該文件的目錄條目仍然存在,直到最後一個打開文件的進程關閉句柄後纔會消失。任何其他嘗試再次打開該文件的進程都會被打上錯誤5,「拒絕訪問」。包括刪除該文件並嘗試重新創建該文件的過程。

解決方法是始終使用「事務性」保存,在嘗試覆蓋文件之前重命名該文件。在.NET中使用File.Replace(),在使用ReplaceFile()的本機winapi中可用。也很容易通過手工完成,工作流程是:

  1. 刪除備份文件,停止,如果失敗
  2. 重命名舊文件到備份文件名,停止,如果失敗
  3. 編寫使用原文件名的新文件如果失敗
  4. 刪除備份文件重命名備份回來,忽略失敗

第二步保證絕不會有任何數據丟失,原來的文件保持不變,如果有什麼差錯。第4步確保FileShare。刪除將按預期工作,當其他進程關閉其句柄時,備份文件將最終消失。

3

我發現,這個再現的場景:

static void Main(string[] args) 
    { 
     string cacheFileName = @"C:\temp.txt"; 
     using (var filestream = new FileStream(cacheFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, 4096, FileOptions.SequentialScan)) 
     { 
      filestream.Read(new byte[100], 1, 1); 
      Console.ReadLine(); 
      GC.KeepAlive(filestream); 
     } 
     Console.WriteLine("Done!"); 
    } 
} 

創建一個 「C:\ TEMP.TXT」 文件,然後運行這個程序。試着用Explorer/TotalCommander刪除文件,它不會抱怨,但它也不會刪除文件。然後,再次運行該程序,它會拋出UnauthorizedAccessException。關閉這兩個.exes之後,它看起來像該文件最終被刪除。

刪除「FileShare.Delete」解決了這個問題,因爲它不會讓您嘗試在使用中刪除文件。

相關問題