技术说明

技术说明

我有一个目录,里面有数百万个子目录和数万亿个文件。现在我必须清除它。我说的万亿,不是文件大小,而是文件数量。

我尝试过del/s使用 和 Windows 资源管理器删除它。两者都无法完成任务。我尝试过逐个删除一些子目录,这花了我好几天的时间。我遇到的问题是,每次,无论使用del或资源管理器,我都可以在任务管理器中看到资源管理器实例消耗了大量内存,并逐渐导致我的系统崩溃。

还有几亿个文件需要删除。是否有可能通过一个(或几个)命令/操作来实现?


[已编辑]

我尝试使用 Cygwin 进行此操作rm -fr,并得到相同的结果。总结如下:

  1. 无论使用 Windows 资源管理器、DEL命令提示符还是 Cygwinrm命令,系统内存都会逐渐降至零,并且盒子最终会崩溃。

  2. 如果在系统发生故障之前的任何时间点关闭了该进程(通过 CTRL+C 或其他方式),则该框将继续正常工作。但是,不会释放所有已使用的内存。假设我在系统内存达到 91% 时停止了该进程,任务管理器显示:总共 4G RAM,缓存为 329M,可用 335MB。然后内存使用率将保持在此水平,直到我重新启动机器。如果我在任务管理器中停止资源管理器实例,屏幕将变为空白,HDD 灯一直亮着,并且永远不会恢复。通常,当我在任务管理器中停止资源管理器实例时,我可以通过按 Win+E 重新调用它,否则它会自动重新启动。

嗯,内存管理确实很好!


[再次编辑] 看来,经过很长一段时间后,一些已使用的内存确实被释放了,但不是全部。一些缓存和可用内存确实在任务管理器中恢复了。我没有再等了,不知道到时候会发生什么。

答案1

我无法谈论数万亿个文件,但我最近使用以下命令删除了一个包含约 180 万个文件的旧文件共享:

robocopy EmptyTMPFolder FolderToDelete /MIR /MT:16 /ETA /R:30 /W:5

“EmptyTMPFolder” 是一个空的本地目录。/MIR 选项将使目标看起来像源(空)。

这种方法的真正好处是重试选项 (/R:30)。这允许有机会解决此过程中可能发生的任何连接问题。本地删除可能无法从这种方法中获益。

我没有具体的基准来比较时间,但我更喜欢这个而不是其他建议的选项,因为有重试/等待选项。删除几乎立即开始。

答案2

技术说明

大多数方法导致问题的原因是 Windows 会尝试枚举文件和文件夹。对于几百甚至几千个文件/文件夹来说,这不是什么大问题,但是当你有万亿数百万个文件夹中的文件,深度达数十层,那么这肯定会导致系统陷入瘫痪。

假设您“只有” 100,000,000 个文件,Windows 使用像这样的简单结构来存储每个文件及其路径(这样您就避免单独存储每个目录,从而节省一些开销):

struct FILELIST {                   // Total size is 264 to 528 bytes:
  TCHAR         name[MAX_PATH];     // MAX_PATH=260; TCHAR=1 or 2 bytes
  FILELIST*     nextfile;           // Pointers are 4 bytes for 32-bit and 8 for 64-bit
}

根据它使用 8 位字符还是 Unicode 字符(它使用 Unicode)以及您的系统是 32 位还是 64 位,它将需要 25GB 到 49GB 的内存来存储列表(这是一个非常简化的结构)。

原因为什么Windows 在删除文件和文件夹之前尝试枚举它们的时间取决于您使用的删除方法,但 Explorer 和命令解释器都会这样做(启动命令时,您可能会看到延迟)。您还可以看到磁盘活动(HDD LED)在从驱动器读取目录树时闪烁。

解决方案

处理这种情况的最佳方法是使用删除工具,逐个删除文件和文件夹。我不知道是否有现成的工具可以做到这一点,但它应该可以通过一个简单的批处理文件来完成。

@echo off
if not [%1]==[] cd /d %1
del /q *
for /d %%i in (*) do call %0 "%%i"

这段代码的作用是检查是否传递了参数。如果传递了参数,则转到指定的目录(您可以不带参数运行它,从当前目录启动,也可以指定目录 — 甚至可以在不同的驱动器上启动它)。

接下来,它会删除当前目录中的所有文件。在此模式下,它不会枚举任何内容,而只是删除文件,不会占用太多内存(如果有的话)。

然后它枚举当前目录并调用自身,将每个文件夹传递给它(自身)以向下递归。

分析

原因是应该之所以有效是因为它没有列举出整棵树。它根本不枚举任何文件,只枚举当前目录中的文件夹(加上其余的这种方法的优点是,它只需要在父目录中找到数百个子目录(而不是父目录中的数百个子目录)。假设任何给定文件夹中只有几百个子目录,那么这应该不会太糟糕,并且肯定比枚举整个树的其他方法所需的内存要少得多。

您可能想知道如何使用/r开关而不是使用(手动)递归。这行不通,因为虽然开关/r会进行递归,但它会预先枚举整个目录树,而这正是我们想要避免的;我们希望在不跟踪的情况下随时删除。

比较

让我们将此方法与完全枚举方法进行比较。

您曾说过您有“数百万个目录”;假设有 1 亿个。如果树大致平衡,并假设每个文件夹平均有 100 个子目录,那么最深的嵌套目录将向下大约四层——实际上,整个树中将有 101,010,100 个子文件夹。(有趣的是,1 亿个可以分解为 100 和 4。)

由于我们没有枚举文件,因此我们只需要跟踪每个级别最多 100 个目录名,以便4 × 100 = 400在任何给定时间内最多跟踪目录。

因此,内存需求应该为~206.25KB,远低于任何现代(或其他)系统的限制范围。

测试

不幸的是(?)我没有一个拥有数百万个文件夹中数万亿个文件的系统,所以我无法测试它(我相信最后统计,我有大约~800K 个文件),所以其他人将不得不尝试它。

警告

当然,内存并不是唯一的限制因素。驱动器也会成为一大瓶颈,因为对于您删除的每个文件和文件夹,系统都必须将其标记为空闲。值得庆幸的是,许多此类磁盘操作将被捆绑在一起(缓存)并以块的形式写出,而不是单独写出(至少对于硬盘驱动器而言,而不是对于可移动媒体而言),但在系统读取和写入数据时,它仍会造成相当大的抖动。

答案3

删除所有文件夹需要很长时间,而且你对此无能为力。你能做的就是保存数据并格式化驱动器。这不是最佳选择,但可以(而且很快)。

另一个选择可能是使用可以从 NTFS 分区读取的实时 CD 上的某些 Linux 发行版。根据我的个人经验,我知道它rm -rf folderName可以运行至少 2 天而不会导致具有 2GB RAM 的系统崩溃。虽然需要一段时间,但至少它会完成。

答案4

Shift+Delete跳过回收站,可能会显著加快速度。

如果这不起作用(极端情况),请尝试快速文件夹擦除器和/或大容量目录擦除器

相关内容