Если вы пытаетесь рекурсивно удалить каталог a
и каталог a\b
открыт в проводнике, b
будет удалено, но вы получите сообщение об ошибке «каталог не пуст» для a
, даже если это пусто, когда вы идете и смотрите. Текущий каталог любого приложения (включая Explorer) сохраняет дескриптор каталога . Когда вы звоните 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
.
Несколько лучшее решение
Этот метод будет обрабатывать удаление глубокой структуры каталогов, даже если в Проводнике открыт один из каталогов нижнего уровня.
/// <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, должно заставить ваши волосы встать.
( Редактировать : много. Этот ответ изначально имел только первое, неполное решение.)