Si está intentando eliminar el directorio de forma recursiva a
y el directorio a\b
está abierto en el Explorador, b
se eliminará, pero obtendrá el error 'el directorio no está vacío' a
, aunque esté vacío cuando vaya y mire. El directorio actual de cualquier aplicación (incluido Explorer) conserva un identificador para el directorio . Cuando llamas Directory.Delete(true)
, se elimina de abajo hacia arriba:, b
entonces a
. Si b
está abierto en Explorer, Explorer detectará la eliminación de b
, cambiará el directorio hacia arriba cd ..
y limpiará los controladores abiertos. Dado que el sistema de archivos funciona de forma asíncrona, la Directory.Delete
operación falla debido a conflictos con Explorer.
Solución incompleta
Originalmente publiqué la siguiente solución, con la idea de interrumpir el hilo actual para permitir que Explorer tenga tiempo de liberar el identificador de directorio.
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
Pero esto solo funciona si el directorio abierto es el hijo inmediato del directorio que está eliminando. Si a\b\c\d
está abierto en el Explorador y lo usa a
, esta técnica fallará después de eliminar d
y c
.
Una solución algo mejor
Este método manejará la eliminación de una estructura de directorio profunda incluso si uno de los directorios de nivel inferior está abierto en el Explorador.
/// <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);
}
}
A pesar del trabajo adicional de recurrir por nuestra cuenta, todavía tenemos que manejar lo UnauthorizedAccessException
que puede ocurrir en el camino. No está claro si el primer intento de eliminación está allanando el camino para el segundo, exitoso, o si es simplemente el retraso de tiempo introducido por lanzar / atrapar una excepción que permite que el sistema de archivos se ponga al día.
Es posible que pueda reducir el número de excepciones lanzadas y atrapadas en condiciones típicas agregando un Thread.Sleep(0)
al comienzo del try
bloque. Además, existe el riesgo de que, bajo una gran carga del sistema, pueda volar a través de ambos Directory.Delete
intentos y fallar. Considere esta solución como un punto de partida para una eliminación recursiva más sólida.
Respuesta general
Esta solución solo aborda las peculiaridades de interactuar con el Explorador de Windows. Si desea una operación de eliminación sólida, una cosa a tener en cuenta es que cualquier cosa (escáner de virus, lo que sea) podría tener un identificador abierto para lo que está tratando de eliminar, en cualquier momento. Entonces tienes que intentarlo más tarde. Cuánto más tarde y cuántas veces lo intente dependerá de lo importante que sea que se elimine el objeto. Como indica MSDN ,
El código robusto de iteración de archivos debe tener en cuenta muchas complejidades del sistema de archivos.
Esta declaración inocente, suministrada solo con un enlace a la documentación de referencia de NTFS, debería poner los pelos de punta.
( Editar : mucho. Esta respuesta originalmente solo tenía la primera solución incompleta).