UnauthorizedAccessException on creating file after deletion using FileStream

半城伤御伤魂 提交于 2019-12-04 20:57:39

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.

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.

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.

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.

When you invoke File.Delete(path), you must give the CPU some time to finish deleting the file before coming back to execute any further code that might have anything to do with the same file name as the one just deleted.

Several ways can accomplish the same thing. Here is how I would do it:

...
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
....
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!