DirectoryInfo.Delete(True)在Windows资源管理器中打开文件夹结构时无法删除。

8
假设我有以下文件夹结构:
C:\MyTemp
   - MySubFolder
如果我尝试使用以下命令删除它:
Dim path As String = "C:\MyTemp"
Dim di As System.IO.DirectoryInfo
di = System.IO.Directory.CreateDirectory(path)
di.CreateSubdirectory("MySubFolder")
di.Delete(True)

这段代码运行正常,但如果我同时打开Windows资源管理器并查看'MySubFolder'目录,则会出现IOException The directory is not empty. - 点击"确定"会消除该错误,但文件夹结构不会被删除。

您有什么想法可以让这段代码在打开Windows资源管理器中的文件夹结构时也能正确执行(即删除)吗?


4
请注意,这是shell的标准行为。您会从rmdir /S得到相同的错误消息。我猜删除操作基本上失败是因为文件资源管理器仍然在使用该子文件夹。 - Dirk Vollmar
@0xA3 - 这不是一致的。请看下面答案中我的评论。有些情况下,我可以在Windows资源管理器中查看文件夹时删除它,然后资源管理器只是导航到已删除的子文件夹的父文件夹。 - Todd Main
@ToddMain 我知道这很旧了,但如果您可以发布解决方案,我将非常感激。 - Ravi Khambhati
4个回答

2

想要 100% 持续的实现这个功能,唯一的方法就是彻底删除资源管理器(不推荐)或者删除句柄(也不推荐,参见此处)。

我的建议是优雅地处理失败,而非试图强制删除。


1

看看这个文章。IOException可能会由打开目录的句柄生成:这个打开的句柄可以通过枚举目录和文件来产生这正是在资源管理器中打开的操作。听起来实际的错误消息是通用的。


是的,我已经读过了,但它指出它仅适用于WinXP及更早版本。其次,假设在MySubfolder下有另一个名为“Temp”的子文件夹和其中一个名为“mypic.jpg”的文件。如果我在Windows资源管理器中查看“Temp”文件夹并使用上面的代码删除它(以及jpg),它确实会被删除。这一点一直不稳定,我不确定该怎么办。 - Todd Main

1

你能做的最好的办法是捕获错误,然后使用handle.exe来找出哪个进程正在使用该文件,并要求用户关闭应用程序,提供“重试”或“取消”的选项。

曾经想知道是哪个程序打开了特定的文件或目录吗?现在你可以找到答案了。Handle是一个显示系统中任何进程的打开句柄信息的实用程序。你可以使用它来查看打开了一个文件的程序,或者查看一个程序的所有句柄的对象类型和名称。

更多信息在这里:

如何使用C#监视进程的IO活动?


0
我想出了以下的DirectoryInfo扩展方法,它包装了本地的DirectoryInfo.Delete()方法,并尝试“安全删除”指定的文件夹:
该方法需要以下COM引用:Microsoft Internet Controls COM Reference:  Microsoft Internet Controls x

    '''' <summary>
    '''' Attempts to perform a "Safe delete" by searching for any Windows File Explorer instances attached to the extended DirectoryInfo Object 
    '''' and navigate those instances off the current DirectoryInfo path in an attempt to prevent a "Directory is not empty" IOException when 
    '''' calling DirectoryInfo.Delete(recursive).
    '''' </summary>
    '''' <param name="DirectoryInfo">The DirectoryInfo object being extended</param>
    '''' <param name="recursive">Optional:  true to delete this directory, its subdirectories, and all files; otherwise false</param>
    '''' <returns>A Boolean indicating whether the DirectoryInfo.Delete(recursive) operation completed without an Exception</returns>
    '''' <remarks>Authored by CMC 2013-05-06 12:04:25 PM</remarks>
    <System.Runtime.CompilerServices.Extension()> _
    Public Function TrySafeDelete(ByVal [DirectoryInfo] As DirectoryInfo, Optional ByVal recursive As Boolean = False, Optional ByVal retryCount As Integer = 0) As Boolean
        Const maxRetryCount As Integer = 10
        retryCount = If(retryCount < 0, 0, retryCount)
        Dim success As Boolean = True
        If ([DirectoryInfo] IsNot Nothing) Then
            [DirectoryInfo].Refresh()
            Dim msWinShellIExplorerWindowsLockingCurrentDirectory As Dictionary(Of SHDocVw.InternetExplorer, DirectoryInfo) = New Dictionary(Of SHDocVw.InternetExplorer, DirectoryInfo)
            If ([DirectoryInfo].Exists()) Then
                Try
                    Dim msWinShellIExplorerWindows As SHDocVw.ShellWindows = New SHDocVw.ShellWindows()
                    For Each msWinShellIExplorerWindow As SHDocVw.InternetExplorer In msWinShellIExplorerWindows
                        If (msWinShellIExplorerWindow.Name.Equals("windows explorer", StringComparison.OrdinalIgnoreCase)) Then
                            Dim locationValue As String = msWinShellIExplorerWindow.LocationURL()
                            If (locationValue.Length() > 0) Then
                                Dim locationURI As Uri = Nothing
                                If (Uri.TryCreate(locationValue, UriKind.RelativeOrAbsolute, locationURI)) Then
                                    Dim msWinShellDirectoryInfo As DirectoryInfo = New DirectoryInfo(locationURI.LocalPath())
                                    Dim isLockingCurrentDirectory As Boolean = msWinShellDirectoryInfo.FullName.ToLower().Contains([DirectoryInfo].FullName.ToLower())
                                    If (isLockingCurrentDirectory AndAlso Not msWinShellIExplorerWindowsLockingCurrentDirectory.ContainsKey(msWinShellIExplorerWindow)) Then msWinShellIExplorerWindowsLockingCurrentDirectory.Add(msWinShellIExplorerWindow, msWinShellDirectoryInfo)
                                End If
                            End If
                        End If
                    Next

                    Dim navigateCompleteCount As Integer = 0
                    If (msWinShellIExplorerWindowsLockingCurrentDirectory.Any()) Then
                        For Each msWinShellDirectoryEntry As KeyValuePair(Of SHDocVw.InternetExplorer, DirectoryInfo) In msWinShellIExplorerWindowsLockingCurrentDirectory
                            Dim msWinShellIExplorerWindow As SHDocVw.InternetExplorer = msWinShellDirectoryEntry.Key()
                            Dim msWinShellDirectoryInfo As DirectoryInfo = msWinShellDirectoryEntry.Value()
                            AddHandler msWinShellIExplorerWindow.NavigateComplete2, New SHDocVw.DWebBrowserEvents2_NavigateComplete2EventHandler(Sub(pDisp As Object, ByRef URL As Object)
                                                                                                                                                     navigateCompleteCount += 1
                                                                                                                                                     If (navigateCompleteCount.Equals(msWinShellIExplorerWindowsLockingCurrentDirectory.Count())) Then
                                                                                                                                                         With [DirectoryInfo]
                                                                                                                                                             .Delete(recursive)
                                                                                                                                                             .Refresh()
                                                                                                                                                         End With
                                                                                                                                                     End If
                                                                                                                                                 End Sub)
                            msWinShellIExplorerWindow.Navigate2(New Uri(msWinShellDirectoryInfo.Root.FullName()).AbsoluteUri())
                        Next
                    Else
                        With [DirectoryInfo]
                            .Delete(recursive)
                            .Refresh()
                        End With
                    End If
                Catch ex As Exception
                End Try

                [DirectoryInfo].Refresh()
                If ([DirectoryInfo].Exists() AndAlso (retryCount <= maxRetryCount)) Then
                    [DirectoryInfo].TrySafeDelete(recursive, retryCount + 1)
                End If
                success = Not DirectoryInfo.Exists()
            End If
        End If
        Return success
    End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接