Якщо ви намагаєтесь рекурсивно видалити каталог a
і каталог a\b
відкрито в Провіднику, b
буде видалено, але ви отримаєте помилку "Каталог не порожній", a
хоча він порожній, коли ви переходите і дивитесь. Поточний каталог будь-якої програми (включаючи Explorer) зберігає обробку до каталогу . Коли ви телефонуєте Directory.Delete(true)
, він видаляється знизу вгору:, b
тоді a
. Якщо b
в Провіднику відкрито, Explorer виявить видалення 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
.
Дещо краще рішення
Цей метод обробляє видалення структури глибокого каталогу, навіть якщо один із каталогів нижчого рівня відкритий у Провіднику.
/// <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
що може відбуватися на цьому шляху. Незрозуміло, чи спроба першого видалення прокладає шлях до другої, успішної, чи це лише затримка в часі, введена викидом / вилученням винятку, що дозволяє файловій системі наздогнати.
Можливо, ви зможете зменшити кількість винятків, викинутих та спійманих у типових умовах, додавши Thread.Sleep(0)
на початку try
блоку. Крім того, існує ризик того, що при великому навантаженні системи ви зможете пролетіти через обидва Directory.Delete
спроби і не вдатися. Розглянемо це рішення вихідною точкою для більш надійного рекурсивного видалення.
Загальна відповідь
Це рішення стосується лише особливостей взаємодії з Windows Explorer. Якщо ви хочете, щоб операція видалення була непростою, слід пам’ятати, що будь-що (сканер вірусів, що завгодно) може мати відкриту ручку до того, що ви намагаєтесь видалити, у будь-який час. Тож вам доведеться спробувати пізніше. Скільки пізніше і скільки разів ви намагаєтесь, залежить від того, наскільки важливо об’єкт видалити. Як вказує MSDN ,
Міцний код ітерації файлів повинен враховувати багато складностей файлової системи.
Ця невинна заява, що постачається лише посиланням на довідкову документацію NTFS, повинна змусити ваші волоски встати.
( Редагувати : Багато. Ця відповідь спочатку мала лише перше, неповне рішення.)