Техническое объяснение
Причина, по которой большинство методов вызывают проблемы, заключается в том, что 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-разрядной, для хранения списка потребуется от 25 до 49 ГБ памяти (и это очень упрощенная структура).
Причина, по которой Windows пытается перечислить файлы и папки перед их удалением, варьируется в зависимости от метода, который вы используете для их удаления, но это делают и Проводник, и интерпретатор команд (вы можете увидеть задержку при запуске команды). Вы также можете увидеть, как мигает индикатор активности диска (HDD), когда он читает дерево каталогов с диска.
Решение
Лучше всего справляться с подобной ситуацией, используя инструмент удаления, который удаляет файлы и папки по отдельности, по одному за раз. Я не знаю, есть ли какие-нибудь готовые инструменты для этого, но это должно быть возможно сделать с помощью простого пакетного файла.
@echo off
if not [%1]==[] cd /d %1
del /q *
for /d %%i in (*) do call %0 "%%i"
Для этого нужно проверить, был ли передан аргумент. Если это так, то он изменяется на указанный каталог (вы можете запустить его без аргумента, чтобы запустить в текущем каталоге или указать каталог - даже на другом диске, чтобы он начинался там).
Далее он удаляет все файлы в текущем каталоге. В этом режиме, он не должен ничего перечислять и просто удалять файлы, не занимая много, если таковые имеются, памяти.
Затем он перечисляет папки в текущем каталоге и вызывает сам себя, передавая ему (себе) каждую папку для рекурсии вниз.
Анализ
Причина, по которой это должно работать, заключается в том, что он не перечисляет каждый отдельный файл и папку во всем дереве. Он не перечисляет файлы вообще, а только перечисляет папки в текущем каталоге (плюс остальные в родительских каталогах). Предполагая, что в любой данной папке есть только несколько сотен подкаталогов, тогда это не должно быть слишком плохо, и, конечно, требует намного меньше памяти, чем другие методы, которые перечисляют все дерево.
Вы можете задуматься об использовании ключа /r
вместо (ручной) рекурсии. Это не сработает, потому что, хотя ключ /r
выполняет рекурсию, он предварительно перечисляет все дерево каталогов, чего мы и хотим избежать; мы хотим удалить, как мы идем, не отслеживая.
сравнение
Давайте сравним этот метод с методом полного перечисления.
Вы сказали, что у вас есть «миллионы каталогов»; скажем 100 миллионов. Если дерево приблизительно сбалансировано и предполагается, что в среднем около 100 подкаталогов на папку, то самый глубокий вложенный каталог будет примерно на четыре уровня ниже - фактически, во всем дереве будет 101 010 100 подпапок. (Забавно, как 100M может сломаться до 100 и 4.)
Поскольку мы не перечисляем файлы, нам нужно отслеживать не более 100 имен каталогов на уровень, максимум 4 × 100 = 400
каталогов в любой момент времени.
Поэтому требование к памяти должно составлять ~ 206,25 КБ, что находится в пределах любой современной (или иной) системы.
Тестовое задание
К несчастью(?) У меня нет системы с триллионами файлов в миллионах папок, поэтому я не могу ее протестировать (я думаю, по последним подсчетам, у меня было около 800 тыс. Файлов), поэтому кто-то другой должен будет попробовать ее.
Предостережение
Конечно, память не единственное ограничение. Диск также будет большим узким местом, потому что для каждого файла и папки, которую вы удаляете, система должна пометить его как свободный. К счастью, многие из этих дисковых операций будут объединены (кэшированы) и записаны в виде кусков, а не по отдельности (по крайней мере, для жестких дисков, а не для съемных носителей), но это все равно будет вызывать небольшие колебания, когда система читает и пишет данные.