如何在 Windows 中安全地递归删除目录?

如何在 Windows 中安全地递归删除目录?

NTFS 支持所有类型的链接,包括连接点、硬链接、软链接等,因此这里存在一个问题。

假设你正在递归删除一个实际上包含上述内容的目录。很容易想象,你的应用程序,不管它是什么,不是删除所有的连接点、软链接这可能会超出您感兴趣的目录等,而是遍历它们并首先删除其中的所有文件。

这很容易导致重大数据丢失。

这是一个简单的例子。你安装了一个装有另一个 Windows 的硬盘驱动器。

让我们检查一下以下内容D:\ProgramData

D:\ProgramData>dir /a
 Volume in drive D has no label.
 Volume Serial Number is 1234-4321

 Directory of D:\ProgramData

12/06/2021  12:56 PM    <DIR>          .
12/06/2021  12:56 PM    <DIR>          ..
07/14/2009  10:08 AM    <JUNCTION>     Application Data [C:\ProgramData]
07/14/2009  10:08 AM    <JUNCTION>     Desktop [C:\Users\Public\Desktop]
07/14/2009  10:08 AM    <JUNCTION>     Documents [C:\Users\Public\Documents]
07/14/2009  10:08 AM    <JUNCTION>     Favorites [C:\Users\Public\Favorites]
02/11/2016  03:51 PM    <DIR>          Microsoft
07/10/2019  03:00 AM    <DIR>          Microsoft Help
12/23/2019  04:04 PM    <DIR>          Package Cache
07/14/2009  10:08 AM    <JUNCTION>     Start Menu [C:\ProgramData\Microsoft\Windows\Start Menu]
07/14/2009  10:08 AM    <JUNCTION>     Templates [C:\ProgramData\Microsoft\Windows\Templates]

现在,如果您尝试递归删除会怎样D:\ProgramData?我甚至不会尝试这样做,因为我担心C:\ProgramData会先被删除。

在 Linux 中rm -rf可以完美地处理这个问题 - 它将符号链接(到目录)视为文件并将符号链接删除,而无需尝试遍历它们。

在 Windows 中递归删除此类目录的安全方法是什么?

rmdir /q /s? 还有别的吗?

答案1

尝试从命令提示符使用 rmdir /s

我创建了一个目录 c:\abc1,其中有一个文本文件。

我创建了一个目录 c:\test1 和一个子目录 c:\test1\blah

在 c:\test1\blah 中我尝试创建到 c:\abc1 的链接,一个符号链接或一个连接链接..

然后,当我对 blah 执行 rmdir /s 时,我检查了 c:\abc1,它仍然在那里,并且包含其内容。

因此,在 Windows 7 中测试的 cmd 提示符下的 rmdir /s 是安全的。

C:\>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,338,368 bytes free

C:\>cd test
The system cannot find the path specified.

C:\>cd test1

C:\test1>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:46    <DIR>          blah
               0 File(s)              0 bytes
               3 Dir(s)  137,425,338,368 bytes free

C:\test1>cd blah

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:46    <DIR>          .
28/12/2021  19:46    <DIR>          ..
               0 File(s)              0 bytes
               2 Dir(s)  137,425,338,368 bytes free

C:\test1\blah>mklink /?
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /d c:\abc1
The syntax of the command is incorrect.
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /d qq c:\abc1
symbolic link created for qq <<===>> c:\abc1

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
28/12/2021  19:47    <SYMLINKD>     qq [c:\abc1]
               0 File(s)              0 bytes
               3 Dir(s)  137,425,469,440 bytes free

C:\test1\blah>dir qq
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah\qq

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,469,440 bytes free

C:\test1\blah>cd ..

C:\test1>rmdir /s blah
blah, Are you sure (Y/N)? y

C:\test1>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,425,379,328 bytes free

C:\test1>cd blah
The system cannot find the path specified.

C:\test1>md blah

C:\test1>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
28/12/2021  19:47    <DIR>          blah
               0 File(s)              0 bytes
               3 Dir(s)  137,424,666,624 bytes free

C:\test1>cd blah

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:47    <DIR>          .
28/12/2021  19:47    <DIR>          ..
               0 File(s)              0 bytes
               2 Dir(s)  137,424,666,624 bytes free

C:\test1\blah>mklink /?
Creates a symbolic link.

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      Creates a directory symbolic link.  Default is a file
                symbolic link.
        /H      Creates a hard link instead of a symbolic link.
        /J      Creates a Directory Junction.
        Link    specifies the new symbolic link name.
        Target  specifies the path (relative or absolute) that the new link
                refers to.

C:\test1\blah>mklink /J ww c:\abc1
Junction created for ww <<===>> c:\abc1

C:\test1\blah>dir
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah

28/12/2021  19:48    <DIR>          .
28/12/2021  19:48    <DIR>          ..
28/12/2021  19:48    <JUNCTION>     ww [c:\abc1]
               0 File(s)              0 bytes
               3 Dir(s)  137,424,715,776 bytes free

C:\test1\blah>dir ww
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of C:\test1\blah\ww

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,424,715,776 bytes free

C:\test1\blah>cd ..

C:\test1>rmdir /s blah
blah, Are you sure (Y/N)? y

C:\test1>dir c:\abc1
 Volume in drive C has no label.
 Volume Serial Number is 4645-5DCE

 Directory of c:\abc1

28/12/2021  19:45    <DIR>          .
28/12/2021  19:45    <DIR>          ..
28/12/2021  19:45                 6 a.txt
               1 File(s)              6 bytes
               2 Dir(s)  137,424,740,352 bytes free

C:\test1>

您确实应该能够非常轻松地自己完成测试。

一条评论提到 powershell rmdir 有所不同。我无法对 powershell 发表太多评论,因为我不怎么使用它。我发现 powershell 的 rmdir 确实给出了不同的输出,例如 rmdir 说“cmdlet Remove-Item at command pipe...”,所以似乎与 cmd 非常不同,我不熟悉它。

答案2

rmdir 将删除符号链接。

del 将删除链接目的地但不会删除链接本身。

rmdir /S /Q将递归删除目录并且不会跟踪符号链接。

我已经测试并确认了 Windows 10 中使用 cmd 的行为:

#create directory structure
C:\Users\username\test>mkdir 1 2 3

C:\Users\username\test>mkdir 1\testdir

C:\Users\username\test>mkdir 1\testdir\1

#create symbolic link to directory

C:\Users\username\test>mklink /D testlink 1\testdir\1
symbolische Verknüpfung erstellt für testlink <<===>> 1\testdir\1


C:\Users\username\test>dir

 Verzeichnis von C:\Users\username\test

28.12.2021  20:24    <DIR>          .
28.12.2021  20:24    <DIR>          ..
28.12.2021  20:23    <DIR>          1
28.12.2021  20:23    <DIR>          2
28.12.2021  20:23    <DIR>          3
28.12.2021  20:24    <SYMLINKD>     testlink [1\testdir\1]
               0 Datei(en),              0 Bytes
               6 Verzeichnis(se), 22.185.267.200 Bytes frei

#test rmdir with the named parameters
C:\Users\username\test>rmdir /s /q testlink

C:\Users\username\test>dir

 Verzeichnis von C:\Users\username\test

28.12.2021  20:25    <DIR>          .
28.12.2021  20:25    <DIR>          ..
28.12.2021  20:23    <DIR>          1
28.12.2021  20:23    <DIR>          2
28.12.2021  20:23    <DIR>          3
               0 Datei(en),              0 Bytes
               5 Verzeichnis(se), 22.185.267.200 Bytes frei



C:\Users\username\test>cd 1\testdir\

#obviously the subdirectory in the linked-to directory is still there
C:\Users\username\test\1\testdir>dir


 Verzeichnis von C:\Users\username\test\1\testdir

28.12.2021  20:23    <DIR>          .
28.12.2021  20:23    <DIR>          ..
28.12.2021  20:24    <DIR>          1
               0 Datei(en),              0 Bytes
               3 Verzeichnis(se), 22.184.206.336 Bytes frei

根据此评论如果从 powershell 调用,rmdir 的行为与从 cmd 调用时的行为不同,但我还没有用 powershell 对其进行测试。

答案3

要删除所有非连接的文件,可以使用以下命令:

del /s /a:-l

在哪里:

  • /s:递归
  • /a:-l:仅限非重新解析点的文件

NTFS 重新解析点 包括目录连接、符号链接和卷挂载点。

可以使用以下命令对将要删除的内容进行小测试:

dir /s /a:-l

(如果它很重要,我仍然会备份该文件夹。)

答案4

FastCopy 实用程序执行以下操作:http://ipmsg.org/tools/fastcopy.html.en

我使用此程序复制或删除可能包含连接点作为子文件夹的文件夹,以便连接点目标保持不变。即使目标驱动器不同,连接点在复制过程中也会被正确复制。

您需要从程序的“主要设置”转到“Shell 扩展”部分并启用它。之后,您将在 Explorer 的右键菜单中看到 Fast Copy-s 删除功能。

Windows 资源管理器(至少在 Windows 7 Ultimate 中)在删除时也能正常工作 - 连接目标保持不变。但在资源管理器中复制包含连接作为子文件夹的文件夹仍然无法按预期工作 - 它实际上做了一些我可能还不能完全描述的事情:连接文件夹似乎被复制为普通文件夹,但其内容为空。

相关内容