Si vous essayez de supprimer récursivement le répertoire a
et que le répertoire a\b
est ouvert dans l'Explorateur, b
il sera supprimé mais vous obtiendrez l'erreur «le répertoire n'est pas vide» car a
même s'il est vide lorsque vous allez regarder. Le répertoire actuel de n'importe quelle application (y compris Explorer) conserve un descripteur sur le répertoire . Lorsque vous appelez Directory.Delete(true)
, il supprime de bas en haut:, b
puis a
. Si b
est ouvert dans Explorer, Explorer détectera la suppression de b
, changera de répertoire vers le haut cd ..
et nettoiera les poignées ouvertes. Étant donné que le système de fichiers fonctionne de manière asynchrone, l' Directory.Delete
opération échoue en raison de conflits avec Explorer.
Solution incomplète
J'ai initialement publié la solution suivante, avec l'idée d'interrompre le thread actuel pour permettre à l'Explorateur de libérer le descripteur de répertoire.
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
Mais cela ne fonctionne que si le répertoire ouvert est l' enfant immédiat du répertoire que vous supprimez. Si a\b\c\d
est ouvert dans l'Explorateur et que vous l'utilisez sur a
, cette technique échouera après la suppression de d
et c
.
Une solution un peu meilleure
Cette méthode gérera la suppression d'une structure de répertoires approfondie même si l'un des répertoires de niveau inférieur est ouvert dans l'Explorateur.
/// <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);
}
}
Malgré le travail supplémentaire de récursivité par nous-mêmes, nous devons encore gérer ce UnauthorizedAccessException
qui peut survenir en cours de route. Il n'est pas clair si la première tentative de suppression ouvre la voie à la deuxième, réussie, ou si c'est simplement le délai de temporisation introduit par le lancement / la capture d'une exception qui permet au système de fichiers de rattraper son retard.
Vous pourriez être en mesure de réduire le nombre d'exceptions levées et interceptées dans des conditions typiques en ajoutant un Thread.Sleep(0)
au début du try
bloc. De plus, il existe un risque que sous une charge système élevée, vous puissiez survoler les deux Directory.Delete
tentatives et échouer. Considérez cette solution comme un point de départ pour une suppression récursive plus robuste.
Réponse générale
Cette solution ne traite que les particularités d'interagir avec l'Explorateur Windows. Si vous voulez une opération de suppression à toute épreuve, une chose à garder à l'esprit est que tout (antivirus, peu importe) pourrait avoir une idée ouverte de ce que vous essayez de supprimer, à tout moment. Vous devez donc réessayer plus tard. Le nombre de tentatives ultérieures et le nombre de tentatives dépendent de l'importance de la suppression de l'objet. Comme l' indique MSDN ,
Un code d'itération de fichier robuste doit prendre en compte de nombreuses complexités du système de fichiers.
Cette déclaration innocente, fournie uniquement avec un lien vers la documentation de référence NTFS, devrait faire lever vos cheveux.
( Edit : Beaucoup. Cette réponse n'avait à l'origine que la première solution incomplète.)