ディレクトリを再帰的に削除しようとしていてa
、ディレクトリa\b
がエクスプローラーで開いている場合、b
は削除されますが、「ディレクトリが空ではありません」というエラーが表示されますa
移動して見ると、ます。アプリケーション(エクスプローラーを含む)の現在のディレクトリは、ディレクトリへのハンドルを保持します。あなたが呼び出すとDirectory.Delete(true)
、それはボトムアップから削除しますb
、そしてa
。b
がエクスプローラーで開いている場合、エクスプローラーはの削除を検出し、b
ディレクトリを上方に変更cd ..
し、開いているハンドルをクリーンアップします。ファイルシステムは非同期で動作するため、Directory.Delete
エクスプローラーとの競合により操作が失敗します。
不完全なソリューション
Explorerがディレクトリハンドルを解放できるように現在のスレッドを中断するという考えで、私は最初に次のソリューションを投稿しました。
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
しかし、これは、オープンディレクトリが が削除するディレクトリの直接の子であるます。a\b\c\d
がエクスプローラーで開いている場合a
、これをで使用するd
と、とを削除すると、この手法は失敗しc
ます。
やや良い解決策
このメソッドは、下位レベルのディレクトリの1つがエクスプローラーで開いている場合でも、深いディレクトリ構造の削除を処理します。
/// <summary>
/// Depth-first recursive delete, with handling for descendant
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
foreach (string directory in Directory.GetDirectories(path))
{
DeleteDirectory(directory);
}
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Directory.Delete(path, true);
}
catch (UnauthorizedAccessException)
{
Directory.Delete(path, true);
}
}
自分で再帰するという余分な作業にもかかわらず、私たちは まだ処理する必要がありますUnauthorizedAccessException
道に沿って発生する可能性があることを。最初の削除の試みが2番目の成功の試みに道を開いているのか、それとも単に例外をスロー/キャッチすることによって引き起こされたタイミング遅延がファイルシステムに追いつくのかを明確にしていない。
を追加することで、一般的な条件下でスローおよびキャッチされる例外の数を減らすことができる場合があります。 Thread.Sleep(0)
try
ブロックの先頭にをあります。さらに、システムの負荷が高い場合、両方のDirectory.Delete
試行を飛ばして失敗する可能性があります。このソリューションを、より堅牢な再帰的削除の開始点と考えてください。
一般的な答え
このソリューションは、Windowsエクスプローラーとのやり取りの特殊性のみを扱います。強固な削除操作が必要な場合は、いつでも(ウイルススキャナーなど)何でも削除しようとしているものへのオープンハンドルが存在する可能性があることに注意してください。したがって、後で再試行する必要があります。どれくらい後で、何回試すかは、オブジェクトを削除することがどれほど重要かによって異なります。MSDNを示し、
堅牢なファイル反復コードは、ファイルシステムの多くの複雑さを考慮する必要があります。
NTFSのリファレンスドキュメントへのリンクのみが提供されているこの無実のステートメントは、あなたの髪を際立たせるはずです。
(編集:たくさん。この答えは当初、最初の不完全な解しかありませんでした。)