2015-02-09 73 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

相关问题