2015-02-09 74 views
1

我在客戶端系統上遇到問題。在試圖用示例代碼重現它時,我已經轉載了它。UnauthorizedAccessException在使用FileStream刪除後創建文件

這裏的示例代碼

Imports System.IO 

Public Class Form1 

    Private _lock As New Object 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
     Dim t As New Threading.Thread(AddressOf createFile) 
     With t 
      .IsBackground = True 
      .Name = Guid.NewGuid.ToString 
      .Start() 
     End With 
    End Sub 

    Private Sub createFile() 
     Dim path As String = "D:\SomeFile.txt" 

     For i As Integer = 0 To 1000 
      SyncLock _lock 
       If File.Exists(path) Then File.Delete(path) 

       Using fs As New FileStream(path, FileMode.CreateNew) 

       End Using 
      End SyncLock  
     Next 
    End Sub 
End Class 

只需運行該代碼,然後單擊按鈕3-4次,注意的異常,如在下面的截圖:

enter image description here

這樣做的堆棧跟蹤例外是:

System.UnauthorizedAccessException was unhand led消息=訪問 路徑'D:\ SomeFile.txt'被拒絕。 Source = mscorlib StackTrace: at System.IO .__ Error.WinIOError(Int32 errorCode,String maybeFullPath) at System.IO.FileStream.Init(String path,FileMode mode,FileAccess access,Int32 rights,Boolean useRights,FileShare share, Int32 bufferSize,FileOptions options,SECURITY_ATTRIBUTES secAttrs, String msgPath,Boolean bFromProxy,Boolean useLongPath) at System.IO.FileStream..ctor(String path,FileMode mode,FileAccess access,FileShare share,Int32 bufferSize,FileOptions options,String msgPath,Boolean bFromProxy) at System.IO.FileStream..ctor(String path,FileMode mode) at WindowsApplication1.Form1.createFile()in C:\ Users \ premjeet.singh \ Desktop \ WindowsApplication1 \ WindowsApplication1 \ Form1.vb :行在System.Threading.ThreadHelper.ThreadStart_Context(對象狀態) 在System.Threading.ExecutionContext.runTryCode(對象的UserData) 在System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode 代碼,CleanupCode backoutCode,對象的UserData) 在System.Threading.ExecutionContext.RunInternal(的ExecutionContext 的ExecutionContext,ContextCallback回調,對象狀態) 在System.Threading.ExecutionContext.Run(的ExecutionContext的ExecutionContext,ContextCallback回調,對象的狀態,布爾 ignoreSyncCtx) 在System.Threading.ExecutionContext .Run(ExecutionContext executionContext,ContextCallback回調,Object狀態) at Sys tem.Threading.ThreadHelper.ThreadStart()的InnerException:

任何人都可以讓我知道這個UnauthorizedAccessException例外,因爲該文件的原因創建新的人之前已被刪除,以及如何解決?

回答

8

這是非常正常的,你正在與你的機器上運行的其他進程戰鬥,這也是對該文件感興趣。更好地稱爲「反惡意軟件」和「搜索索引器」。 「點擊3次」的場景就是那些其他進程需要一段時間才能看到文件內容的失敗模式。

此類流程將打開文件進行刪除共享,以最大限度地降低其影響。 .NET中提供了相同的功能,FileShare.Delete option。這在某種程度上起作用,因爲在發現時刪除文件沒有任何問題。但該文件實際上不會從文件系統中消失,除非其他進程關閉文件上的句柄。雖然它仍然存在,但任何試圖打開或覆蓋掛起 - 刪除文件的進程都會被「拒絕訪問」錯誤打上耳光。

一般來說,你從不想要使用你現在使用的方法,刪除文件,然後嘗試重新創建它。鑑於這可能會失敗的可能性很大,您將根本沒有文件留下用戶。這是不可挽回的數據丟失。替代方法是交換該文件,由File.Replace()方法支持。這對於鎖定的文件很好,這些進程只鎖定文件數據,而不鎖定目錄條目。換句話說,你可以重命名這個文件沒有問題。

Private Function createFile(ByVal outpath As String) As Boolean 
    Dim temp As String = Path.Combine(Path.GetDirectoryName(outpath), Guid.NewGuid.ToString()) 
    Dim bak As String = outpath + ".bak" 
    '' Create the file first 
    Using fs As New FileStream(temp, FileMode.CreateNew) 
     ''... 
    End Using 
    '' Now try to swap it in place 
    Try 
     File.Delete(bak) 
     File.Replace(temp, outpath, bak) 
    Catch 
     File.Delete(temp) 
     Return False 
    End Try 
    '' That worked, don't need the backup anymore. Failure to delete is not fatal 
    Try 
     File.Delete(bak) 
    Catch 
    End Try 
    Return True 
End Function 

這仍然是不完美的,但是對於數據丟失的可能性被消除,你給是在文件上更多的時間用它來完成該過程。您是否想要在交換操作周圍設置重試循環取決於您。

技術上可以做到完美,你必須給備份文件名指定一個隨機名,這樣下次創建文件時永遠不會失敗。然而,這將文件噴到磁盤上,難以擺脫。如果你這樣做,那麼你還必須將文件移動到驅動器的回收站,以便它在未來將被刪除一些日。幸運的是,在VB.NET中很容易做到,使用DeleteFile()輔助函數並指定RecycleOption.SendToRecycleBin。但只有在保存到本地驅動器時才適用。

+1

這似乎是對問題的真正解釋,非常感謝Hans the Great ...... :) – prem 2015-02-11 11:29:15

-4

當你調用File.Delete(path)時,你必須給CPU一些時間來完成刪除文件,然後再回來執行任何進一步的代碼,這些代碼可能與剛纔刪除的文件名相同。

幾種方法可以完成同樣的事情。下面是我該怎麼做:

... 
If File.Exists(path) Then 
    File.Delete(path) 

    Application.DoEvents() 'Force completing any pending events 
          'immediately start deleting the file 

    System.Threading.Thread.Sleep(1000)  'optional: wait 1 second 

    While System.IO.File.Exists(path) 'In case the file is still in 
             ' the process of being deleted 
             ' Wait here for it to finish 
    End While 


    Using fs As New FileStream(path, FileMode.CreateNew) 'Now create the file 

End If 
.... 
+2

爲什麼顯式等待檢查文件被刪除?使用Thread.Sleep或一個無限循環並不是一個好的編程習慣,而是爲什麼File.Delete在刪除完成之前沒有等待自己? – prem 2015-02-11 10:38:34

+2

爲了您的利益,我想提一些建議[Application.DoEvents](http://stackoverflow.com/a/5183623/495455)幾乎總是一個壞主意。如果沒有嘗試捕獲,用戶就有更高的機會看到問題:** UnauthorizedAccessException **,並且在特殊情況下(我承認很少,很少取決於HDD/NAS,防病毒,文件鎖定等)可能會導致代碼陷入'while'循環導致一個凍結的應用程序。 – 2015-02-14 14:08:05

相關問題