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

Posted

技术标签:

【中文标题】DirectoryInfo.Delete(True) 在 Windows 资源管理器中打开文件夹结构时不删除【英文标题】:DirectoryInfo.Delete(True) Doesn't Delete When Folder Structure is Open in Windows Explorer 【发布时间】:2011-05-05 09:31:02 【问题描述】:

假设我的文件夹结构如下:

C:\MyTemp
   - 我的子文件夹

如果我尝试使用以下方法删除它:

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 目录不是空的。 - 单击 OK 会关闭它,然后文件夹结构不会被删除。

我有什么想法可以让它正确执行(即删除),即使在 Windows 资源管理器中打开文件夹结构时运行此代码?

【问题讨论】:

请注意,这是 shell 的标准行为。您将从rmdir /S 收到相同的错误消息。我猜删除基本上失败了,因为资源管理器仍然有一个打开子文件夹的句柄。 @0xA3 - 不一致。请参阅我对以下答案的评论。在某些情况下,我可以在 Windows 资源管理器中查看文件夹时删除它,然后资源管理器只是导航到被删除的子文件夹的父文件夹。 @ToddMain 我知道这是旧的,但如果你能发布解决方案,我将不胜感激。 【参考方案1】:

唯一能让这个“工作”100% 始终如一的方法是对 explorer 进行核对(坏主意)或对句柄进行核对(also bad idea)

我的建议是优雅地处理失败,而不是尝试这样做。

【讨论】:

【参考方案2】:

看看这个article。 IOException 可以从目录的打开句柄生成:This open handle can result from enumerating directories and files,这正是在资源管理器中打开的作用。听起来实际的错误消息是通用的。

【讨论】:

是的,我已经读过,但它声明它仅适用于 WinXP 和更早版本。其次,假设在 MySubfolder 下我有另一个名为“Temp”的子文件夹和一个名为“mypic.jpg”的文件。如果我在 Windows 资源管理器中查看“Temp”文件夹并使用上面的代码删除它(和 jpg),它确实会删除。一直不一致,我不知道该怎么办。【参考方案3】:

您能做的最好的事情就是捕获错误,然后使用handle.exe 找出正在使用该文件的进程并要求用户关闭应用程序并选择重试取消

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

这里有更多信息:

How to monitor process' IO activity using C#?

【讨论】:

【参考方案4】:

我想出了以下 DirectoryInfo 扩展方法,它包装了本机 DirectoryInfo.Delete() 方法并尝试“安全删除”指定文件夹:

此方法需要以下 COM 引用: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

【讨论】:

以上是关于DirectoryInfo.Delete(True) 在 Windows 资源管理器中打开文件夹结构时不删除的主要内容,如果未能解决你的问题,请参考以下文章

为啥 TRUE == "TRUE" 在 R 中为 TRUE?

2022-09-30:以下go语言代码输出什么?A: true true false true false; B: true false false true false; C: true true

java 里面true & true 或者true & false是啥意思?

为啥我的测试以 true == true 失败

为啥“[False, True] 中的 not(True)”返回 False?

Django UUIDFIeld unique=True、blank=True 和 null=True 的行为是不是正确?