Se você estiver tentando excluir o diretório recursivamente a
e o diretório a\b
estiver aberto no Explorer, b
ele será excluído, mas o erro 'diretório não está vazio' será exibido, a
mesmo que esteja vazio quando você olhar. O diretório atual de qualquer aplicativo (incluindo o Explorer) mantém um identificador no diretório . Quando você liga Directory.Delete(true)
, ele exclui de baixo para cima:, b
então a
. Se b
estiver aberto no Explorer, o Explorer detectará a exclusão b
, alterará o diretório para cima cd ..
e limpará os identificadores abertos. Como o sistema de arquivos opera de forma assíncrona, a Directory.Delete
operação falha devido a conflitos com o Explorer.
Solução incompleta
Originalmente, publiquei a seguinte solução, com a idéia de interromper o segmento atual para permitir que o tempo do Explorer libere o identificador de diretório.
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
Mas isso só funciona se o diretório aberto for o filho imediato do diretório que você está excluindo. Se a\b\c\d
estiver aberto no Explorer e você o usar a
, essa técnica falhará após excluir d
e c
.
Uma solução um pouco melhor
Esse método manipulará a exclusão de uma estrutura de diretórios profunda, mesmo que um dos diretórios de nível inferior esteja aberto no Explorer.
/// <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);
}
}
Apesar do trabalho extra de repetir por conta própria, ainda temos que lidar com o UnauthorizedAccessException
que pode ocorrer ao longo do caminho. Não está claro se a primeira tentativa de exclusão está abrindo caminho para a segunda, bem-sucedida, ou se é apenas o atraso de tempo introduzido ao lançar / capturar uma exceção que permite ao sistema de arquivos recuperar o atraso.
Você pode reduzir o número de exceções lançadas e capturadas em condições típicas adicionando uma Thread.Sleep(0)
no início do try
bloco. Além disso, existe o risco de que, sob carga pesada do sistema, você possa passar pelas Directory.Delete
tentativas e falhar. Considere esta solução como um ponto de partida para uma exclusão recursiva mais robusta.
Resposta geral
Esta solução aborda apenas as peculiaridades da interação com o Windows Explorer. Se você deseja uma operação de exclusão sólida, lembre-se de que qualquer coisa (antivírus, qualquer que seja) pode ter um identificador aberto para o que você está tentando excluir, a qualquer momento. Então você tem que tentar novamente mais tarde. Quanto mais tarde e quantas vezes você tenta depende de quão importante é que o objeto seja excluído. Como o MSDN indica ,
O código robusto de iteração de arquivo deve levar em consideração muitas complexidades do sistema de arquivos.
Essa declaração inocente, fornecida apenas com um link para a documentação de referência do NTFS, deve fazer você se arrepiar.
( Edit : Muita. Esta resposta originalmente tinha apenas a primeira solução incompleta.)