UnauthorizedAccessException使用删除后的FileStream创建文件文件、UnauthorizedAccessException、FileStream

2023-09-03 15:19:55 作者:犯賤的是妳,狼狽的卻是我

我现在面临的客户端系统的问题。在试图重现它在一个样本code我已经转载了。

I am facing an issue on client system. On trying to reproduce it in a sample code I have reproduced it.

下面的示例code

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

只要运行这​​个code和点击按钮3-4次,如在下面的截图注意到异常:

Just Run this code and click the button 3-4 times and notice the exception as shown in screenshot below:

这异常的堆栈跟踪是:

System.UnauthorizedAccessException的是未处理消息=访问   路径D:\ SomeFile.txt'被拒绝。来源= mscorlib程序堆栈跟踪:          在System.IO .__ Error.WinIOError(的Int32错误code,字符串maybeFullPath)          在System.IO.FileStream.Init(字符串路径,的FileMode模式,FileAccess的访问,的Int32权,布尔useRights,文件共享份额,   INT32 BUFFERSIZE,FileOptions选项,SECURITY_ATTRIBUTES secAttrs,   字符串MSGPATH,布尔bFromProxy,布尔useLongPath)          在System.IO.FileStream..ctor(字符串路径,的FileMode模式,FileAccess的访问,文件共享份额,的Int32缓冲区大小,FileOptions   选项​​字符串MSGPATH,布尔bFromProxy)          在System.IO.FileStream..ctor(字符串路径,的FileMode模式)          在WindowsApplication1.Form1.createFile()在C:\用户\ premjeet.singh \桌面\的WindowsApplication1 \的WindowsApplication1 \ Form1.vb的:行   23          在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)          在System.Threading.ExecutionContext.runTry code(对象USERDATA)          在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code   code,清理code撤销code,对象USERDATA)          在System.Threading.ExecutionContext.RunInternal(执行上下文   执行上下文,ContextCallback回调,对象的状态)          在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态,布尔   ignoreSyncCtx)          在System.Threading.ExecutionContext.Run(ExecutionContext中的ExecutionContext,ContextCallback回调,对象的状态)          在System.Threading.ThreadHelper.ThreadStart()的InnerException:

System.UnauthorizedAccessException was unhandled Message=Access to the path 'D:\SomeFile.txt' is denied. 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:line 23 at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.runTryCode(Object userData) at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:

任何人都可以让我知道这个UnauthorizedAccessException异常的原因是该文件在创建新的前已经删除,以及它如何可以解决?

Can anybody let me know the reason for this UnauthorizedAccessException exception as the file is already deleted before creating the new one and how it can be solved?

推荐答案

这是pretty的正常的,你正在做的战斗,你的机器上运行的也有兴趣在文件中其他进程。更好地称为反恶意软件和搜索索引。 点击3次的情况仅仅是故障模式下,通过采取而其他进程诱使去看看,看到该文件的内容。

This is pretty normal, you are doing battle with other processes that run on your machine that are also interested in the file. Better known as "anti-malware" and "search indexer". The "click 3 times" scenario is just the failure-mode you induce by those other processes taking a while to have a look-see at the file content.

这样的过程将打开文件进行删除共享,以最大限度地降低其影响。同样的功能在.NET中,FileShare.Delete选项​​。这样的作品,在一定程度上,你没有任何麻烦删除的文件,你发现了。但该文件实际上不会从文件系统消失,直到那些其他进程关闭的文件的句柄。虽然它仍然存在,任何试图打开或覆盖待处理,删除文件的过程将被处以拒绝访问错误。

Such processes will open the file for delete sharing to minimize their impact. Same capability is exposed in .NET, FileShare.Delete option. That works, to a degree, you don't have any trouble deleting the file as you found out. But the file will not actually disappear from the file system until those other processes close their handle on the file. While it still exists, any process that tries to open or overwrite the pending-delete file will be slapped with an "access denied" error.

在一般情况下,你的永远的想用你现在使用的方法,删除文件,然后试图重新创建它。鉴于重重困难,这可能会失败,你会离开的用户,没有文件在所有。这就是数据的不可挽回的损失。另一种方法是交换的文件,通过的 File.Replace()方法。这对于锁定的文件效果很好,这些方法只对文件数据的锁,而不是在目录条目。换句话说,你可以的改名的无故障文件。

In general, you never want to use the approach you use now, deleting the file and then trying to recreate it. Given the considerable odds that this can fail, you'll leave the user with no file at all. That's irrecoverable loss of data. The alternative is to swap the file, supported by the File.Replace() method. Which works well for locked files, these processes only have a lock on the file data, not on the directory entry. In other words, you can rename the file without trouble.

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

这仍然是不完美的,但赔率数据丢失被淘汰,你给了持有该文件更多的时间用它来完成这个过程。无论你是想将重试环周围的交换操作是由你。

This still isn't perfect but the odds for data loss are eliminated and you give the process that is holding on the file more time to finish using it. Whether you want to put a retry-loop around the swap operation is up to you.

从技术上讲,可以使其完美的,你必须给备份文件名随机的名字,所以你永远不能失败,在创建该文件的下一次将其删除。这不过喷洒文件是很难摆脱的磁盘。如果你这样做,那么你还必须将文件移动到驱动器的回收站所以它会被删除的部分的一天,在未来的。幸运的是,这是容易做到的VB.NET,使用的DeleteFile()辅助功能,并指定RecycleOption.SendToRecycleBin。但是,只有合适的,如果你保存到本地驱动器。

Technically it is possible to make it perfect, you have to give the backup filename a random name so you can never fail to delete it the next time you create the file. That however sprays files to the disk that are hard to get rid of. If you do this then you must also move the file to the drive's Recycle Bin so it will get deleted some day in the future. Luckily that's easy to do in VB.NET, use the DeleteFile() helper function and specify RecycleOption.SendToRecycleBin. But only appropriate if you save to a local drive.