Si vous essayez de supprimer récursivement un répertoire a
et le répertoire a\b
est ouvert dans l'Explorer, b
sera supprimé mais vous obtiendrez l'erreur 'le répertoire n'est pas vide' pour a
même si elle est vide quand on y va et qu'on la regarde. Le répertoire actuel de toute application (y compris l'Explorateur) conserve un handle sur le répertoire . Lorsque vous appelez Directory.Delete(true)
il supprime de bas en haut : b
entonces a
. Si b
est ouvert dans l'Explorateur, ce dernier détectera la suppression de l'adresse de l'utilisateur. b
, changer de répertoire vers le haut cd ..
et nettoyer les poignées ouvertes. Étant donné que le système de fichiers fonctionne de manière asynchrone, la fonction Directory.Delete
échoue en raison de conflits avec Explorer.
Solution incomplète
J'ai initialement posté la solution suivante, avec l'idée d'interrompre le fil de discussion en cours pour laisser à Explorer le temps de libérer le gestionnaire 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 le immédiat enfant du répertoire que vous supprimez. Si a\b\c\d
est ouvert dans Explorer et que vous l'utilisez sur a
cette technique échouera après avoir supprimé d
y c
.
Une solution un peu meilleure
Cette méthode permet de gérer la suppression d'une structure de répertoire profonde, 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 que représente la récursion par nous-mêmes. toujours doivent gérer les UnauthorizedAccessException
qui peuvent se produire en cours de route. Il n'est pas clair si la première tentative de suppression ouvre la voie à la deuxième tentative réussie, ou si c'est simplement le délai introduit par le lancement/la capture d'une exception qui permet au système de fichiers de rattraper son retard.
Vous pouvez peut-être réduire le nombre d'exceptions levées et rattrapées dans des conditions normales en ajoutant une fonction Thread.Sleep(0)
au début de la try
bloc. En outre, il existe un risque que, en cas de forte charge du système, vous puissiez traverser les deux blocs de l Directory.Delete
tentent et échouent. 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 prend en compte que les particularités de l'interaction avec l'Explorateur Windows. Si vous voulez une opération de suppression solide comme le roc, il faut garder à l'esprit que n'importe quel élément (scanner de virus, etc.) peut avoir un accès ouvert à ce que vous essayez de supprimer, à tout moment. Vous devez donc réessayer plus tard. Le délai et le nombre de tentatives dépendent de l'importance de la suppression de l'objet. Comme MSDN indique ,
Un code robuste d'itération de fichiers doit prendre en compte de nombreuses complexités du système de fichiers.
Cette affirmation innocente, accompagnée d'un simple lien vers la documentation de référence NTFS, devrait vous faire dresser les cheveux sur la tête.
( Modifier : Beaucoup. Cette réponse n'avait à l'origine que la première solution, incomplète).
14 votes
Vous ne verriez pas d'exception AccessViolationException -- c'est pour les opérations sur les pointeurs invalides, pas pour l'accès au disque.
1 votes
Il semble qu'il s'agisse d'un problème d'entrée-sortie autre que le fait que le répertoire ne soit pas vide, comme des poignées de fichiers ouvertes ou autre. J'essaierais d'utiliser l'option de suppression récursive, puis dans une capture pour IOException, de rechercher et de fermer tous les poignées de fichiers ouverts, puis de réessayer. Il y a une discussion à ce sujet ici : stackoverflow.com/questions/177146/