技術説明
ほとんどの方法が問題を引き起こしている理由は、Windowsがファイルとフォルダーを列挙しようとするためです。これは、数百または数千のファイル/フォルダが数レベルの深さで問題になることはほとんどありませんが、数百のフォルダに数十億のファイルがあり、数十レベルの深さになると、システムが完全に動かなくなります。 。
「100」個の「ファイル」のみがあるとします。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がファイルとフォルダーを削除する前に列挙しようとする理由は、それらを削除するために使用している方法によって異なりますが、エクスプローラーとコマンドインタープリターの両方がそれを行います(コマンドを開始すると遅延が見られます)。また、ドライブからディレクトリツリーを読み取る際に、ディスクアクティビティ(HDD LED)フラッシュを確認できます。
解決
この種の状況に対処する最善の方法は、ファイルとフォルダーを個別に1つずつ削除する削除ツールを使用することです。それを行うための既製のツールがあるかどうかはわかりませんが、単純なバッチファイルで達成できるはずです。
@echo off
if not [%1]==[] cd /d %1
del /q *
for /d %%i in (*) do call %0 "%%i"
これは、引数が渡されたかどうかを確認することです。その場合は、指定されたディレクトリに変更します(引数なしで実行して現在のディレクトリで開始するか、ディレクトリを指定できます(別のドライブでも開始できます)。
次に、現在のディレクトリ内のすべてのファイルを削除します。このモードでは、何も列挙せず、ファイルを削除するだけで、メモリを大量に消費することはありません。
次に、現在のディレクトリ内のフォルダーを列挙し、それ自体を呼び出して、各フォルダーをそのフォルダーに渡し(自己)、下方に再帰します。
分析
これが機能する理由は、ツリー全体のすべてのファイルとフォルダーを列挙しないためです。ファイルはまったく列挙されず、現在のディレクトリ内のフォルダー(および親ディレクトリ内の残りのフォルダー)のみが列挙されます。特定のフォルダにサブディレクトリが数百個しかない場合、これはそれほど悪くないはずであり、ツリー全体を列挙する他のメソッドよりも必要なメモリは確実に少なくなります。
/r
(手動)再帰を使用する代わりに、スイッチを使用することについて疑問に思うかもしれません。/r
スイッチは再帰を実行しますが、ディレクトリツリー全体を事前に列挙するため、これは機能しません。追跡せずに移動すると削除したいです。
比較
このメソッドを完全列挙メソッドと比較してみましょう。
「数百万のディレクトリ」があると言っていました。1億としましょう。ツリーのバランスがほぼ取れており、フォルダーごとに平均で約100個のサブディレクトリを想定すると、ネストされた最も深いディレクトリは約4レベル下になります。実際には、ツリー全体に101,010,100個のサブフォルダがあります。(100Mがどのように100と4に分解できるかを考えてください。)
ファイルを列挙していないため、レベルごとに最大100個のディレクトリ名を追跡するだけでよく4 × 100 = 400
、任意の時点で最大のディレクトリが必要です。
したがって、メモリ要件は約206.25KBである必要があり、これは現代の(またはその他の)システムの制限内です。
テスト
残念ながら(?)何百万ものフォルダーに何兆ものファイルがあるシステムがないので、テストすることができません(最後のカウントでは約800K個のファイルがあったと信じています)ので、誰かが試してみる必要がありますそれ。
警告
もちろん、メモリだけが制限ではありません。ドライブは、削除するすべてのファイルとフォルダーに対して、システムが空きとしてマークする必要があるため、大きなボトルネックになります。ありがたいことに、これらのディスク操作の多くは一緒にバンドル(キャッシュ)され、個別にではなくチャンクに書き出されます(少なくともリムーバブルメディアではなくハードドライブに対して)が、システムが読み取るときにかなりのスラッシングが発生しますデータを書き込みます。