Impossible de supprimer le répertoire avec Directory.Delete (chemin, vrai)

383

J'utilise .NET 3.5, essayant de supprimer récursivement un répertoire en utilisant:

Directory.Delete(myPath, true);

Ma compréhension est que cela devrait jeter si des fichiers sont en cours d'utilisation ou s'il y a un problème d'autorisations, mais sinon cela devrait supprimer le répertoire et tout son contenu.

Cependant, j'obtiens parfois ceci:

System.IO.IOException: The directory is not empty.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
    ...

Je ne suis pas surpris que la méthode lance parfois, mais je suis surpris de recevoir ce message particulier lorsque récursif est vrai. (Je sais que le répertoire n'est pas vide.)

Y a-t-il une raison pour laquelle je verrais ceci au lieu de AccessViolationException?

Jason Anderson
la source
13
Vous ne verriez pas AccessViolationException - c'est pour les opérations de pointeur non valides, pas pour l'accès au disque.
Joe White,
1
Cela semble être une sorte de problème d'E / S autre que le répertoire qui n'est pas vide, comme les descripteurs de fichiers ouverts ou quelque chose. J'essaierais d'utiliser l'option de suppression récursive, puis dans une capture pour IOException, rechercher et fermer tous les descripteurs de fichiers ouverts, puis réessayer. Il y a une discussion à ce sujet ici: stackoverflow.com/questions/177146/…
Dan Csharpster

Réponses:

231

Note de l'éditeur: Bien que cette réponse contienne des informations utiles, elle est incorrecte sur le fonctionnement de Directory.Delete. Veuillez lire les commentaires de cette réponse et les autres réponses à cette question.


J'ai rencontré ce problème auparavant.

La racine du problème est que cette fonction ne supprime pas les fichiers qui se trouvent dans la structure du répertoire. Donc, ce que vous devrez faire est de créer une fonction qui supprime tous les fichiers de la structure de répertoires puis tous les répertoires avant de supprimer le répertoire lui-même. Je sais que cela va à l'encontre du deuxième paramètre, mais c'est une approche beaucoup plus sûre. En outre, vous souhaiterez probablement supprimer les attributs d'accès en lecture seule des fichiers juste avant de les supprimer. Sinon, cela déclenchera une exception.

Insérez simplement ce code dans votre projet.

public static void DeleteDirectory(string target_dir)
{
    string[] files = Directory.GetFiles(target_dir);
    string[] dirs = Directory.GetDirectories(target_dir);

    foreach (string file in files)
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }

    foreach (string dir in dirs)
    {
        DeleteDirectory(dir);
    }

    Directory.Delete(target_dir, false);
}

De plus, pour moi, j'ajoute personnellement une restriction sur les zones de la machine qui peuvent être supprimées car voulez-vous que quelqu'un appelle cette fonction sur C:\WINDOWS (%WinDir%)ou C:\.

Jeremy Edwards
la source
117
Ça n'a pas de sens. Directory.Delete (myPath, true) est une surcharge qui supprime tous les fichiers qui se trouvent dans la structure de répertoires. Si vous voulez vous tromper, trompez-vous avec la réponse de Ryan S.
Sig. Tolleranza
35
+1 car bien que Directory.Delete () supprime les fichiers dans ses sous-répertoires (avec récursif = true), il lève une "IOException: le répertoire n'est pas vide" si l'un des sous-répertoires ou fichiers est en lecture seule. Cette solution fonctionne donc mieux que Directory.Delete ()
Anthony Brien
17
Votre déclaration qui Directory.Delete(path, true)ne supprime pas les fichiers est incorrecte. Voir MSDN msdn.microsoft.com/en-us/library/fxeahc5f.aspx
Konstantin Spirin
20
-1 Quelqu'un peut-il indiquer clairement que la validité de cette approche est fortement mise en doute? En cas d' Directory.Delete(string,bool)échec, quelque chose est verrouillé ou mal autorisé et il n'y a pas de solution unique à un tel problème. Les gens doivent aborder ce problème dans leur contexte et nous ne devrions pas faire grandir chaque idée du problème (avec des tentatives et une déglutition d'exception) et en espérant un bon résultat.
Ruben Bartelink
37
Méfiez-vous de cette approche si votre répertoire que vous supprimez contient des raccourcis / liens symboliques vers d'autres dossiers - vous pouvez finir par supprimer plus que prévu
Chanakya
182

Si vous essayez de supprimer récursivement le répertoire aet que le répertoire a\best ouvert dans l'Explorateur, bil sera supprimé mais vous obtiendrez l'erreur «le répertoire n'est pas vide» car amê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:, bpuis a. Si best 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.Deleteopé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\dest ouvert dans l'Explorateur et que vous l'utilisez sur a, cette technique échouera après la suppression de det 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 UnauthorizedAccessExceptionqui 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 trybloc. De plus, il existe un risque que sous une charge système élevée, vous puissiez survoler les deux Directory.Deletetentatives 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.)

ryscl
la source
11
Il apparaît en appelant Directory.Delete (chemin, vrai) tandis que le chemin ou l'un des dossiers / fichiers sous chemin est ouvert ou sélectionné dans l'Explorateur Windows lèvera une IOException. La fermeture de l'Explorateur Windows et la réexécution de mon code existant sans le try / catch suggéré ci-dessus ont bien fonctionné.
David Alpert
1
Je ne peux pas comprendre comment et pourquoi cela fonctionne, mais cela a fonctionné pour moi tout en définissant les attributs de fichier et en écrivant ma propre fonction récursive.
Stilgar
1
@CarlosLiu Parce que cela donne à "Explorer une chance de libérer le descripteur de répertoire"
Dmitry Gonchar
4
Ce qui se passe, c'est que le système demande à Explorer de "libérer le descripteur de répertoire", puis essaie de supprimer le répertoire. Si le descripteur de répertoire n'a pas été supprimé à temps, une exception est déclenchée et le catchbloc est exécuté (en attendant, Explorer libère toujours le répertoire, car aucune commande n'a été envoyée pour lui dire de ne pas le faire). L'appel à Thread.Sleep(0)peut être nécessaire ou non, car le catchbloc a déjà donné un peu plus de temps au système, mais il offre un peu de sécurité supplémentaire pour un faible coût. Après cela, le Deleteest appelé, avec le répertoire déjà publié.
Zachary Kniebel
1
@PandaWood en fait seul ce sommeil (100) a fonctionné pour moi. Le sommeil (0) ne fonctionnait pas. Je n'ai aucune idée de ce qui se passe et comment résoudre ce problème correctement. Je veux dire, que se passe-t-il si cela dépend de la charge du serveur et qu'à l'avenir il devrait y en avoir 300 ou 400? Comment le savoir. Ce doit être une autre manière appropriée ...
Roman
43

Avant d'aller plus loin, vérifiez les raisons suivantes qui sont sous votre contrôle:

  • Le dossier est-il défini comme répertoire actuel de votre processus? Si oui, changez-le d'abord en autre chose.
  • Avez-vous ouvert un fichier (ou chargé une DLL) à partir de ce dossier? (et j'ai oublié de le fermer / décharger)

Sinon, vérifiez les raisons légitimes suivantes hors de votre contrôle:

  • Il y a des fichiers marqués en lecture seule dans ce dossier.
  • Vous ne disposez pas d'une autorisation de suppression pour certains de ces fichiers.
  • Le fichier ou le sous-dossier est ouvert dans l'Explorateur ou une autre application.

Si l'un des problèmes ci-dessus pose problème, vous devez comprendre pourquoi cela se produit avant d'essayer d'améliorer votre code de suppression. Au cas où votre application est la suppression des fichiers en lecture seule ou inaccessibles? Qui les a marqués de cette façon et pourquoi?

Une fois que vous avez exclu les raisons ci-dessus, il y a toujours une possibilité de fausses pannes. La suppression échouera si quelqu'un détient une poignée sur l'un des fichiers ou dossiers en cours de suppression, et il existe de nombreuses raisons pour lesquelles quelqu'un peut énumérer le dossier ou lire ses fichiers:

  • indexeurs de recherche
  • anti-virus
  • logiciel de sauvegarde

L'approche générale pour gérer les pannes parasites consiste à essayer plusieurs fois, en faisant une pause entre les tentatives. Vous ne voulez évidemment pas continuer à essayer pour toujours, vous devez donc abandonner après un certain nombre de tentatives et lever une exception ou ignorer l'erreur. Comme ça:

private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
    const int magicDust = 10;
    for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
        try {
            Directory.Delete(destinationDir, true);
        } catch (DirectoryNotFoundException) {
            return;  // good!
        } catch (IOException) { // System.IO.IOException: The directory is not empty
            System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);

            // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
            Thread.Sleep(50);
            continue;
        }
        return;
    }
    // depending on your use case, consider throwing an exception here
}

À mon avis, un assistant comme celui-ci devrait être utilisé pour toutes les suppressions car des pannes parasites sont toujours possibles. Cependant, VOUS DEVEZ ADAPTER CE CODE À VOTRE CAS D'UTILISATION, pas simplement le copier à l'aveugle.

J'ai eu de fausses pannes pour un dossier de données interne généré par mon application, situé sous% LocalAppData%, donc mon analyse se présente comme suit:

  1. Le dossier est contrôlé uniquement par mon application, et l'utilisateur n'a aucune raison valable d'aller marquer des choses en lecture seule ou inaccessibles dans ce dossier, donc je n'essaie pas de gérer ce cas.

  2. Il n'y a rien de précieux créé par l'utilisateur, donc il n'y a aucun risque de supprimer de force quelque chose par erreur.

  3. Étant un dossier de données interne, je ne m'attends pas à ce qu'il soit ouvert dans l'explorateur, au moins je ne ressens pas le besoin de gérer spécifiquement le cas (c'est-à-dire que je gère bien ce cas via le support).

  4. Si toutes les tentatives échouent, je choisis d'ignorer l'erreur. Dans le pire des cas, l'application ne parvient pas à décompresser certaines ressources plus récentes, se bloque et invite l'utilisateur à contacter le support, ce qui est acceptable pour moi tant que cela ne se produit pas souvent. Ou, si l'application ne plante pas, elle laissera des anciennes données derrière moi, ce qui est encore acceptable pour moi.

  5. J'ai choisi de limiter les tentatives à 500 ms (50 * 10). Il s'agit d'un seuil arbitraire qui fonctionne dans la pratique; Je voulais que le seuil soit suffisamment court pour que les utilisateurs ne tuent pas l'application, pensant qu'elle a cessé de répondre. D'un autre côté, une demi-seconde donne amplement de temps au délinquant pour terminer le traitement de mon dossier. À en juger par d'autres réponses SO qui trouvent parfois même Sleep(0)acceptables, très peu d'utilisateurs connaîtront jamais plus d'une seule nouvelle tentative.

  6. Je réessaie toutes les 50 ms, ce qui est un autre nombre arbitraire. Je pense que si un fichier est en cours de traitement (indexé, vérifié) lorsque j'essaie de le supprimer, 50 ms est à peu près le bon moment pour s'attendre à ce que le traitement soit terminé dans mon cas. En outre, 50 ms est suffisamment petit pour ne pas entraîner de ralentissement notable; encore une fois, Sleep(0)semble être suffisant dans de nombreux cas, nous ne voulons donc pas trop tarder.

  7. Le code réessaye toutes les exceptions d'E / S. Je ne m'attends normalement à aucune exception à l'accès à% LocalAppData%, j'ai donc choisi la simplicité et accepté le risque d'un retard de 500 ms en cas d'exception légitime. Je ne voulais pas non plus trouver un moyen de détecter l'exception exacte sur laquelle je veux réessayer.

Andrey Tarantsov
la source
7
PPS Quelques mois plus tard, je suis heureux d'annoncer que ce morceau de code (quelque peu fou) a complètement résolu le problème. Les demandes d'assistance concernant ce problème sont tombées à zéro (environ 1 à 2 par semaine).
Andrey Tarantsov
1
+0 Bien que ce soit plus robuste et moins «le voici; la solution parfaite pour vous »que stackoverflow.com/a/7518831/11635 , pour moi la même chose s'applique - programmation par coïncidence - manipulez avec soin. Un point utile incorporé dans votre code est que si vous voulez faire une nouvelle tentative, vous devez considérer que vous êtes dans une course avec l'ambiguïté de savoir si le répertoire a «disparu» depuis la dernière tentative [et un Directory.Existsgarde niave le ferait pas résoudre cela.]
Ruben Bartelink
1
j'adore ... je ne sais pas ce que je fais que c'est toujours un problème pour moi ... mais ce n'est pas parce que j'ai le répertoire ouvert dans l'explorateur ... pas beaucoup de tollé sur internet à ce sujet plus -ou-moins de bogue ... au moins moi et Andrey avons un moyen de le gérer :)
TCC
2
@RubenBartelink OK, donc je pense que nous pouvons nous mettre d'accord sur ce point: publier un morceau de code qui fonctionne pour une application spécifique (et n'a jamais été conçu pour convenir à chaque cas), car une réponse SO va être un mauvais service pour de nombreux novices et / ou des développeurs ignorants. Je l'ai donné comme point de départ pour la personnalisation, mais oui, certaines personnes vont l'utiliser tel quel, et c'est une mauvaise chose.
Andrey Tarantsov
2
@nopara Vous n'avez pas besoin de la comparaison; si nous sommes hors de la boucle, nous avons échoué. Et oui, dans de nombreux cas, vous voudrez lever l'exception, puis ajouter le code de gestion des erreurs approprié dans la pile, probablement avec un message visible par l'utilisateur.
Andrey Tarantsov
18

Réponse Async Moderne

La réponse acceptée est tout simplement fausse, cela pourrait fonctionner pour certaines personnes car le temps nécessaire pour obtenir des fichiers à partir du disque libère tout ce qui bloquait les fichiers. Le fait est que cela se produit parce que les fichiers sont verrouillés par un autre processus / flux / action. Les autres réponses utilisent Thread.Sleep(Yuck) pour réessayer de supprimer le répertoire après un certain temps. Cette question doit être revisitée avec une réponse plus moderne.

public static async Task<bool> TryDeleteDirectory(
   string directoryPath,
   int maxRetries = 10,
   int millisecondsDelay = 30)
{
    if (directoryPath == null)
        throw new ArgumentNullException(directoryPath);
    if (maxRetries < 1)
        throw new ArgumentOutOfRangeException(nameof(maxRetries));
    if (millisecondsDelay < 1)
        throw new ArgumentOutOfRangeException(nameof(millisecondsDelay));

    for (int i = 0; i < maxRetries; ++i)
    {
        try
        {
            if (Directory.Exists(directoryPath))
            {
                Directory.Delete(directoryPath, true);
            }

            return true;
        }
        catch (IOException)
        {
            await Task.Delay(millisecondsDelay);
        }
        catch (UnauthorizedAccessException)
        {
            await Task.Delay(millisecondsDelay);
        }
    }

    return false;
}

Tests unitaires

Ces tests montrent un exemple de la façon dont un fichier verrouillé peut provoquer l' Directory.Deleteéchec de et comment la TryDeleteDirectoryméthode ci-dessus résout le problème.

[Fact]
public async Task TryDeleteDirectory_FileLocked_DirectoryNotDeletedReturnsFalse()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var result = await TryDeleteDirectory(directoryPath, 3, 30);
            Assert.False(result);
            Assert.True(Directory.Exists(directoryPath));
        }
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

[Fact]
public async Task TryDeleteDirectory_FileLockedThenReleased_DirectoryDeletedReturnsTrue()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        Task<bool> task;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            task = TryDeleteDirectory(directoryPath, 3, 30);
            await Task.Delay(30);
            Assert.True(Directory.Exists(directoryPath));
        }

        var result = await task;
        Assert.True(result);
        Assert.False(Directory.Exists(directoryPath));
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}
Muhammad Rehan Saeed
la source
Pouvez-vous développer ce que vous entendez par «moderne»? Quels sont les avantages de votre approche? Pourquoi les autres, à votre avis, ont-ils tort?
TinyRacoon
1
D'autres n'ont pas tort. Ils utilisent simplement des API plus anciennes comme celles Thread.Sleepque vous devriez éviter aujourd'hui et utiliser async/ awaitavec à la Task.Delayplace. C'est compréhensible, c'est une très vieille question.
Muhammad Rehan Saeed
Cette approche ne fonctionnera pas dans VB.Net (du moins pas avec une conversion ligne à ligne très littérale) en raison deBC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
amonroejj
@amonroejj Vous devez utiliser une ancienne version. Cela a été corrigé.
Muhammad Rehan Saeed
Petite amélioration au lieu de retourner vrai if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); pour attendre que le répertoire soit vraiment parti
fuchs777
16

Une chose importante qui doit être mentionnée (je l'ai ajoutée en tant que commentaire mais je n'y suis pas autorisé) est que le comportement de la surcharge est passé de .NET 3.5 à .NET 4.0.

Directory.Delete(myPath, true);

À partir de .NET 4.0, il supprime les fichiers dans le dossier lui-même mais PAS dans 3.5. Cela peut également être vu dans la documentation MSDN.

.NET 4.0

Supprime le répertoire spécifié et, si indiqué, tous les sous-répertoires et fichiers du répertoire.

.NET 3.5

Supprime un répertoire vide et, si indiqué, tous les sous-répertoires et fichiers du répertoire.

jettatore
la source
3
Je pense que ce n'est qu'un changement de documentation ... s'il ne supprime qu'un "répertoire vide", qu'est-ce que cela signifierait de supprimer aussi les fichiers du répertoire, avec le paramètre 2 °? S'il est vide, il n'y a pas de fichiers ...
Pisu
Je crains que vous ne vous trompiez. J'ai posté cela après avoir testé le code avec les deux versions du framework. La suppression d'un dossier non vide en 3.5 lèvera une exception.
jettatore
15

J'ai eu le même problème sous Delphi. Et le résultat final était que ma propre application bloquait le répertoire que je voulais supprimer. D'une manière ou d'une autre, le répertoire s'est verrouillé lorsque j'écrivais dessus (certains fichiers temporaires).

Le catch 22 était, j'ai fait un simple changement de répertoire vers son parent avant de le supprimer.

Drejc
la source
6
+1 Il y a maintenant quelque chose que msdn pour Directory.Delete mentionne!
Ruben Bartelink
3
une solution finale avec un échantillon complet de code source qui fonctionne?
Kiquenet
11

Je suis surpris que personne n'ait pensé à cette méthode simple non récursive, qui peut supprimer des répertoires contenant des fichiers en lecture seule, sans avoir besoin de changer l'attribut en lecture seule de chacun d'eux.

Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles"); 

(Changez un peu pour ne pas déclencher une fenêtre cmd momentanément, qui est disponible partout sur Internet)

Piyush Soni
la source
Agréable à partager avec nous, mais seriez-vous assez aimable pour inclure le peu de changement nécessaire pour empêcher le déclenchement de la fenêtre cmd, au lieu de nous inciter à le rechercher sur le net?
ThunderGr
Ça ne marche pas. Dans la même situation où je peux supprimer le fichier à partir d'une invite de commande ou de l'Explorateur, l'utilisation de ce code pour appeler rmdir donne le code de sortie 145 qui se traduit par "Le répertoire n'est pas vide". Il laisse le répertoire vide mais toujours en place, exactement comme Directory.Delete ("", vrai)
Kevin Coulombe
@Kevin Coulombe, Humm ... Êtes-vous sûr d'utiliser les commutateurs / s / q?
Piyush Soni
1
@KevinCoulombe: Oui, ce doit être ces composants COM. Quand j'essaye par le simple vieux C #, cela fonctionne et il supprime le répertoire avec les fichiers à l'intérieur (en lecture seule ou non en lecture seule).
Piyush Soni
5
Si vous commencez à compter sur des composants externes pour ce qui devrait être dans le cadre, c'est une idée "moins qu'idéale" car elle n'est plus portable (ou plus difficile). Et si l'exe n'est pas là? Ou l'option / a-t-elle changé? Si la solution de Jeremy Edwards fonctionne, elle devrait être préférée à
mon humble avis
11

Vous pouvez reproduire l'erreur en exécutant:

Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");

Lorsque vous essayez de supprimer le répertoire 'b', il lève l'exception IOException "Le répertoire n'est pas vide". C'est stupide puisque nous venons de supprimer le répertoire 'c'.

D'après ma compréhension, l'explication est que le répertoire «c» est estampillé comme supprimé. Mais la suppression n'est pas encore validée dans le système. Le système a répondu que le travail est terminé, alors qu'en fait, il est toujours en cours de traitement. Le système attend probablement que l'explorateur de fichiers se concentre sur le répertoire parent pour valider la suppression.

Si vous regardez le code source de la fonction Supprimer ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ), vous verrez qu'il utilise la fonction native Win32Native.RemoveDirectory. Ce comportement de non-attente est noté ici:

La fonction RemoveDirectory marque un répertoire à supprimer à la fermeture. Par conséquent, le répertoire n'est supprimé que lorsque la dernière poignée du répertoire est fermée.

( http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx )

Dormir et réessayer est la solution. Cf la solution du ryascl.

Olivier de Rivoyre
la source
8

J'ai eu ces problèmes d'autorisation étranges lors de la suppression des répertoires de profil utilisateur (dans C: \ Documents and Settings) malgré le fait de pouvoir le faire dans le shell de l'Explorateur.

File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);

Cela n'a aucun sens pour moi ce que fait une opération "fichier" sur un répertoire, mais je sais que cela fonctionne et cela me suffit!

p.campbell
la source
2
Toujours pas d'espoir, lorsque le répertoire contient de nombreux fichiers et que l'Explorateur ouvre le dossier contenant ces fichiers.
voit
3

Cette réponse est basée sur: https://stackoverflow.com/a/1703799/184528 . La différence avec mon code, c'est que nous ne récursions que de nombreux sous-répertoires et fichiers de suppression lorsque cela est nécessaire, un appel à Directory.Delete échoue lors d'une première tentative (ce qui peut se produire lorsque l'explorateur Windows regarde un répertoire).

    public static void DeleteDirectory(string dir, bool secondAttempt = false)
    {
        // If this is a second try, we are going to manually 
        // delete the files and sub-directories. 
        if (secondAttempt)
        {
            // Interrupt the current thread to allow Explorer time to release a directory handle
            Thread.Sleep(0);

            // Delete any files in the directory 
            foreach (var f in Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly))
                File.Delete(f);

            // Try manually recursing and deleting sub-directories 
            foreach (var d in Directory.GetDirectories(dir))
                DeleteDirectory(d);

            // Now we try to delete the current directory
            Directory.Delete(dir, false);
            return;
        }

        try
        {
            // First attempt: use the standard MSDN approach.
            // This will throw an exception a directory is open in explorer
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        }
        catch (UnauthorizedAccessException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        } 
    }
cdiggins
la source
Alors, comment est-il censé supprimer le dossier s'il y en avait un UnauthorizedAccessException? Cela lancerait simplement, encore une fois. Et encore. Et encore une fois ... Parce qu'à chaque fois, ça va aller à la catchet appeler à nouveau la fonction. A Thread.Sleep(0);ne change pas vos autorisations. Il devrait simplement enregistrer l'erreur et échouer correctement, à ce stade. Et cette boucle continuera juste tant que le (sous-) répertoire est ouvert - il ne le ferme pas par programme. Sommes-nous prêts à le laisser faire aussi longtemps que ces choses restent ouvertes? Y a-t-il une meilleure façon?
vapcguy
S'il y en a un, UnauthorizedAccessExceptionil essaiera manuellement de supprimer chaque fichier manuellement. Il continue donc de progresser en se déplaçant dans la structure du répertoire. Oui, potentiellement chaque fichier et répertoire lèvera la même exception, mais cela peut également se produire simplement parce que l'explorateur y tient un handle (voir stackoverflow.com/a/1703799/184528 ) Je changerai le "tryAgain" en "secondTry" pour le rendre plus clair.
cdiggins
Pour répondre plus succinctement, il passe "true" et exécute un chemin de code différent.
cdiggins
À droite, vu votre modification, mais mon point de vue n'est pas la suppression de fichiers, mais la suppression du répertoire. J'ai écrit du code où je pourrais faire essentiellement Process.Kill()sur n'importe quel processus par lequel un fichier peut être verrouillé et supprimer les fichiers. Le problème que je rencontre est lors de la suppression d'un répertoire où l'un de ces fichiers était encore ouvert (voir stackoverflow.com/questions/41841590/… ). Donc, en revenant dans cette boucle, peu importe ce qu'il fait d'autre, s'il Directory.Delete()recommence sur ce dossier, il échouera toujours si cette poignée ne peut pas être libérée.
vapcguy
Et la même chose se produirait pour un, UnauthorizedAccessExceptioncar la suppression de fichiers (en supposant que cela soit même autorisé, car pour accéder à ce code, il a échoué Directory.Delete()) ne vous donne pas par magie la permission de supprimer le répertoire.
vapcguy
3

Aucune des solutions ci-dessus n'a bien fonctionné pour moi. J'ai fini par utiliser une version modifiée de la solution @ryascl comme ci-dessous:

    /// <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))
        {
            Thread.Sleep(1);
            DeleteDir(directory);
        }
        DeleteDir(path);
    }

    private static void DeleteDir(string dir)
    {
        try
        {
            Thread.Sleep(1);
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            DeleteDir(dir);
        }
        catch (UnauthorizedAccessException)
        {
            DeleteDir(dir);
        }
    }
cahit beyaz
la source
2

Est-il possible que vous ayez une condition de concurrence critique où un autre thread ou processus ajoute des fichiers au répertoire:

La séquence serait:

Processus Deleter A:

  1. Vider le répertoire
  2. Supprimez le répertoire (maintenant vide).

Si quelqu'un d'autre ajoute un fichier entre 1 et 2, alors peut-être que 2 lèverait l'exception répertoriée?

Douglas Leeder
la source
2

J'ai passé quelques heures à résoudre ce problème et d'autres exceptions avec la suppression du répertoire. C'est ma solution

 public static void DeleteDirectory(string target_dir)
    {
        DeleteDirectoryFiles(target_dir);
        while (Directory.Exists(target_dir))
        {
            lock (_lock)
            {
                DeleteDirectoryDirs(target_dir);
            }
        }
    }

    private static void DeleteDirectoryDirs(string target_dir)
    {
        System.Threading.Thread.Sleep(100);

        if (Directory.Exists(target_dir))
        {

            string[] dirs = Directory.GetDirectories(target_dir);

            if (dirs.Length == 0)
                Directory.Delete(target_dir, false);
            else
                foreach (string dir in dirs)
                    DeleteDirectoryDirs(dir);
        }
    }

    private static void DeleteDirectoryFiles(string target_dir)
    {
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }

        foreach (string dir in dirs)
        {
            DeleteDirectoryFiles(dir);
        }
    }

Ce code a le petit retard, ce qui n'est pas important pour mon application. Mais attention, le délai peut être un problème pour vous si vous avez beaucoup de sous-répertoires dans le répertoire que vous souhaitez supprimer.

Demid
la source
8
-1 Quel est le retard? Pas de programmation par coïncidence s'il vous plait!
Ruben Bartelink
1
@Ruben Je n'ai pas dit que vous vous trompiez. Je viens de dire que le vote négatif pour celui-ci est une punition sévère. Je suis d'accord avec vous, cependant, les 4 votes positifs n'avaient pas donné lieu à 4 votes négatifs. Je voterais aussi pour votre commentaire, mais je ne revaudrais pas la réponse en raison d'un retard inexpliqué :)
ThunderGr
1
@RubenBartelink et autres: bien que je n'aime pas spécifiquement ce code (j'ai posté une autre solution avec une approche similaire), le délai ici est raisonnable. Le problème est très probablement hors du contrôle de l'application; peut-être qu'une autre application réanalyse périodiquement le FS, verrouillant ainsi le dossier pendant de courtes périodes. Le retard résout le problème en obtenant le compte à rebours à zéro. Peu importe si nous n'avons aucune idée de la cause profonde?
Andrey Tarantsov
1
@RubenBartelink En fait, quand vous y pensez, ne pas utiliser une approche de délai et de nouvelle tentative pendant la suppression du répertoire NTFS est une solution irresponsable ici. Tout type de traversée de fichier en cours bloque la suppression, il est donc voué à l'échec tôt ou tard. Et vous ne pouvez pas vous attendre à ce que tous les outils tiers de recherche, de sauvegarde, d'antivirus et de gestion de fichiers restent en dehors de votre dossier.
Andrey Tarantsov
1
@RubenBartelink Un autre exemple, disons que vous donnez un délai de 100 ms, et le temps de verrouillage le plus élevé de tous les logiciels sur le PC cible est le logiciel AV = 90 ms. Supposons qu'il dispose également d'un logiciel de sauvegarde qui verrouille les fichiers pendant 70 ms. Maintenant, l'AV verrouille un fichier, votre application attend 100 ms, ce qui est normalement bien, mais rencontre ensuite un autre verrou parce que le logiciel de sauvegarde commence à saisir le fichier à la marque 70 ms de l'analyse AV, et il faudra donc encore 40 ms pour libérer le fichier. Ainsi, alors que le logiciel AV prend plus de temps et que vos 100 ms sont normalement plus longs que l'une des 2 applications, vous devez toujours tenir compte du moment où il démarre au milieu.
vapcguy
2

La suppression récursive du répertoire qui ne supprime pas les fichiers est certainement inattendue. Ma solution pour cela:

public class IOUtils
{
    public static void DeleteDirectory(string directory)
    {
        Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
        Directory.Delete(directory, true);
    }
}

J'ai rencontré des cas où cela a aidé, mais généralement, Directory.Delete supprime les fichiers à l'intérieur des répertoires lors d'une suppression récursive, comme indiqué dans msdn .

De temps en temps, je rencontre ce comportement irrégulier également en tant qu'utilisateur de l'Explorateur Windows: Parfois, je ne peux pas supprimer un dossier (il pense que le message absurde est "accès refusé") mais lorsque j'explore et supprime les éléments inférieurs, je peux ensuite supprimer le supérieur articles aussi. Je suppose donc que le code ci-dessus traite d'une anomalie du système d'exploitation - pas d'un problème de bibliothèque de classe de base.

citykid
la source
1

Le répertoire ou un fichier qu'il contient est verrouillé et ne peut pas être supprimé. Trouvez le coupable qui l'a verrouillé et voyez si vous pouvez l'éliminer.

Vilx-
la source
T1000 à l'utilisateur avec dossier ouvert: "Vous avez terminé!"
vapcguy
1

Il semble qu'avoir le chemin ou le sous-dossier sélectionné dans l'Explorateur Windows soit suffisant pour bloquer une seule exécution de Directory.Delete (chemin, vrai), lançant une IOException comme décrit ci-dessus et mourant au lieu de démarrer l'Explorateur Windows dans un dossier parent et de procéder comme attendu.

David Alpert
la source
Cela semble avoir été mon problème. Dès que j'ai fermé Explorer et que j'ai couru à nouveau, aucune exception. Même sélectionner le parent du parent n'était pas suffisant. J'ai dû fermer réellement Explorer.
Scott Marlowe
Oui, cela arrive et c'est une cause. Donc, une idée de la façon de le gérer par programme, ou la réponse est-elle toujours de s'assurer que tous les 1000 utilisateurs ont ce dossier fermé?
vapcguy
1

J'ai eu ce problème aujourd'hui. Cela se produisait parce que j'avais Windows Explorer ouvert sur le répertoire qui essayait d'être supprimé, provoquant l'échec de l'appel récursif et donc l'IOException. Assurez-vous qu'il n'y a pas de descripteurs ouverts dans le répertoire.

De plus, MSDN est clair que vous n'avez pas à écrire votre propre récusion: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx

GrokSrc
la source
1

J'ai eu ce même problème avec Windows Workflow Foundation sur un serveur de génération avec TFS2012. En interne, le flux de travail appelé Directory.Delete () avec l'indicateur récursif défini sur true. Il semble être lié au réseau dans notre cas.

Nous supprimions un dossier de dépôt binaire sur un partage réseau avant de le recréer et de le remplir à nouveau avec les derniers fichiers binaires. Toutes les autres versions échoueraient. Lors de l'ouverture du dossier de dépôt après une génération ayant échoué, le dossier était vide, ce qui indique que tous les aspects de l'appel Directory.Delete () ont réussi, à l'exception de la suppression du répertoire réel.

Le problème semble être dû à la nature asynchrone des communications de fichiers réseau. Le serveur de génération a dit au serveur de fichiers de supprimer tous les fichiers et le serveur de fichiers a signalé que oui, même s'il n'était pas complètement terminé. Ensuite, le serveur de génération a demandé que le répertoire soit supprimé et le serveur de fichiers a rejeté la demande car il n'avait pas complètement terminé la suppression des fichiers.

Deux solutions possibles dans notre cas:

  • Construisez la suppression récursive dans notre propre code avec des retards et des vérifications entre chaque étape
  • Réessayez jusqu'à X fois après une IOException, ce qui donne un délai avant de réessayer

Cette dernière méthode est rapide et sale mais semble faire l'affaire.

Shaun
la source
1

Cela est dû à FileChangesNotifications.

Cela se produit depuis ASP.NET 2.0. Lorsque vous supprimez un dossier dans une application, il est redémarré . Vous pouvez le voir vous-même, à l'aide de la surveillance de la santé ASP.NET .

Ajoutez simplement ce code à votre web.config / configuration / system.web:

<healthMonitoring enabled="true">
  <rules>
    <add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
  </rules>
</healthMonitoring>


Après cette vérification Windows Log -> Application. Que se passe-t-il:

Lorsque vous supprimez un dossier, s'il existe un sous-dossier, Delete(path, true)supprimez d'abord le sous-dossier. Il suffit que FileChangesMonitor connaisse la suppression et fermez votre application. Pendant ce temps, votre répertoire principal n'est pas encore supprimé. Voici l'événement de Log:


entrez la description de l'image ici


Delete() n'a pas terminé son travail et parce que l'application est en cours de fermeture, il déclenche une exception:

entrez la description de l'image ici

Lorsque vous n'avez aucun sous-dossier dans un dossier que vous supprimez, Delete () supprime simplement tous les fichiers et ce dossier, l'application redémarre également, mais vous ne recevez aucune exception , car le redémarrage de l'application n'interrompt rien. Mais vous perdez toutes les sessions en cours, l'application ne répond pas aux demandes lors du redémarrage, etc.

Et maintenant?

Il existe des solutions et des ajustements pour désactiver ce comportement, Directory Junction , Turning Off FCN with Registry , Stopping FileChangesMonitor using Reflection (puisqu'il n'y a pas de méthode exposée) , mais ils ne semblent pas tous avoir raison, car FCN est là pour un raison. Il s'occupe de la structure de votre application , qui n'est pas la structure de vos données . La réponse courte est: placez les dossiers que vous souhaitez supprimer en dehors de votre application. FileChangesMonitor ne recevra aucune notification et votre application ne sera pas redémarrée à chaque fois. Vous n'aurez aucune exception. Pour les rendre visibles sur le Web, il existe deux manières:

  1. Créez un contrôleur qui gère les appels entrants et sert ensuite les fichiers en lisant à partir du dossier en dehors d'une application (en dehors de wwwroot).

  2. Si votre projet est volumineux et que les performances sont les plus importantes, configurez un serveur Web petit et rapide séparé pour diffuser du contenu statique. Ainsi vous laisserez à IIS son métier spécifique. Il peut s'agir de la même machine (mangouste pour Windows) ou d'une autre machine (nginx pour Linux). Bonne nouvelle, vous n'avez pas à payer de licence Microsoft supplémentaire pour configurer un serveur de contenu statique sur Linux.

J'espère que cela t'aides.

romain
la source
1

Comme mentionné ci-dessus, la solution "acceptée" échoue sur les points d'analyse - pourtant les gens la marquent toujours (???). Il existe une solution beaucoup plus courte qui reproduit correctement la fonctionnalité:

public static void rmdir(string target, bool recursive)
{
    string tfilename = Path.GetDirectoryName(target) +
        (target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
        Path.GetRandomFileName();
    Directory.Move(target, tfilename);
    Directory.Delete(tfilename, recursive);
}

Je sais, ne gère pas les cas d'autorisations mentionnés plus tard, mais à toutes fins utiles, FAR BETTER fournit les fonctionnalités attendues du répertoire original / stock.Delete () - et avec beaucoup moins de code aussi .

Vous pouvez poursuivre le traitement en toute sécurité, car l'ancien répertoire sera hors de portée ... même s'il n'est pas parti parce que le `` système de fichiers est toujours en train de rattraper son retard '' (ou toute autre excuse que MS a donnée pour fournir une fonction cassée) .

Comme avantage, si vous savez que votre répertoire cible est grand / profond et que vous ne voulez pas attendre (ou déranger avec des exceptions), la dernière ligne peut être remplacée par:

    ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });

Vous êtes toujours en sécurité pour continuer à travailler.

Rob
la source
2
Votre affectation peut-elle être simplifiée par: string tfilename = Path.Combine (Path.GetDirectoryName (target), Path.GetRandomFileName ());
Pete
1
Je dois être d'accord avec Pete. Le code tel qu'il est écrit n'ajoutera pas le séparateur. Il a pris mon chemin \\server\C$\diret l'a fait \\server\C$asf.yuw. En conséquence, j'ai eu une erreur sur le Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. A bien fonctionné une fois que j'ai utilisé le code de Pete SAUF ni les poignées lorsqu'il y a des fichiers verrouillés ou des répertoires ouverts, donc il n'obtient jamais la ThreadPoolcommande.
vapcguy
ATTENTION: cette réponse ne doit être utilisée qu'avec récursif = vrai. Si false, cela déplacera le répertoire même s'il n'est pas vide. Ce serait un bug; le comportement correct dans ce cas est de lever une exception et de laisser le répertoire tel qu'il était.
ToolmakerSteve
1

Ce problème peut apparaître sous Windows lorsqu'il existe des fichiers dans un répertoire (ou dans n'importe quel sous-répertoire) dont la longueur de chemin d'accès est supérieure à 260 symboles.

Dans de tels cas, vous devez supprimer \\\\?\C:\mydirau lieu de C:\mydir. À propos de la limite de 260 symboles, vous pouvez lire ici .

HostageBrain
la source
1

J'ai résolu avec cette technique millénaire (vous pouvez laisser le fil. Dormir tout seul dans la prise)

bool deleted = false;
        do
        {
            try
            {
                Directory.Delete(rutaFinal, true);                    
                deleted = true;
            }
            catch (Exception e)
            {
                string mensaje = e.Message;
                if( mensaje == "The directory is not empty.")
                Thread.Sleep(50);
            }
        } while (deleted == false);
Mauricio Rdz
la source
0

Si le répertoire actuel de votre application (ou de toute autre application) est celui que vous essayez de supprimer, il ne s'agira pas d'une erreur de violation d'accès mais un répertoire n'est pas vide. Assurez-vous que ce n'est pas votre propre application en changeant le répertoire courant; assurez-vous également que le répertoire n'est pas ouvert dans un autre programme (par exemple, Word, Excel, Total Commander, etc.). La plupart des programmes seront enregistrés dans le répertoire du dernier fichier ouvert, ce qui provoquerait cela.

configurateur
la source
0

en cas de fichiers réseau, Directory.DeleteHelper (récursif: = true) peut provoquer une exception IOException causée par le retard de la suppression du fichier

affairé
la source
0

Je pense qu'il y a un fichier ouvert par un flux dont vous n'êtes pas au courant. J'ai eu le même problème et je l'ai résolu en fermant tous les flux qui pointaient vers le répertoire que je voulais supprimer.

Ahmad Moussa
la source
0

Cette erreur se produit si un fichier ou un répertoire est considéré comme en cours d'utilisation. C'est une erreur trompeuse. Vérifiez si vous avez des fenêtres d'explorateur ou des fenêtres de ligne de commande ouvertes sur n'importe quel répertoire de l'arborescence ou un programme qui utilise un fichier dans cette arborescence.

allen1
la source
0

J'ai résolu une instance possible du problème déclaré lorsque les méthodes étaient asynchrones et codées comme ceci:

// delete any existing update content folder for this update
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
       await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

Avec ça:

bool exists = false;                
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
    exists = true;

// delete any existing update content folder for this update
if (exists)
    await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

Conclusion? Il y a un aspect asynchrone à se débarrasser de la poignée utilisée pour vérifier l'existence dont Microsoft n'a pas pu parler. C'est comme si la méthode asynchrone dans une instruction if avait l'instruction if agissant comme une instruction using.

Pat Pattillo
la source
0

Vous n'avez pas besoin de créer et de méthode supplémentaire pour la récursivité ou de supprimer des fichiers dans le dossier supplémentaire. Tout cela se fait automatiquement en appelant

DirectoryInfo.Delete ();

Les détails sont ici .

Quelque chose comme ça fonctionne assez bien:

  var directoryInfo = new DirectoryInfo("My directory path");
    // Delete all files from app data directory.

    foreach (var subDirectory in directoryInfo.GetDirectories())
    {
          subDirectory.Delete(true);// true set recursive paramter, when it is true delete sub file and sub folder with files too
    }

passer true comme variable pour supprimer la méthode supprimera également les sous-fichiers et le sous-dossier contenant les fichiers.

nzrytmn
la source
-2

Aucune des réponses ci-dessus n'a fonctionné pour moi. Il semble que l'utilisation de ma propre application DirectoryInfosur le répertoire cible le faisait rester verrouillé.

Forcer la collecte des ordures semble résoudre le problème, mais pas tout de suite. Quelques tentatives de suppression si nécessaire.

Notez le Directory.Existscar il peut disparaître après une exception. Je ne sais pas pourquoi la suppression a été retardée pour moi (Windows 7 SP1)

        for (int attempts = 0; attempts < 10; attempts++)
        {
            try
            {
                if (Directory.Exists(folder))
                {
                    Directory.Delete(folder, true);
                }
                return;
            }
            catch (IOException e)
            {
                GC.Collect();
                Thread.Sleep(1000);
            }
        }

        throw new Exception("Failed to remove folder.");
Reactgular
la source
1
-1 Programmation par coïncidence. Quel objet fait quoi quand GC'd? Est-ce en quelque sorte un bon conseil général? (Je vous crois quand vous dites que vous avez eu un problème et que vous avez utilisé ce code et que vous sentez que vous n'avez pas de problème maintenant, mais ce n'est pas le problème)
Ruben Bartelink
@RubenBartelink Je suis d'accord. C'est un hack. Code vaudou qui fait quelque chose quand il n'est pas clair ce qu'il résout ou comment. J'aimerais une bonne solution.
Reactgular à 11h59
1
Mon problème est que tout ce qu'il ajoute au-delà de stackoverflow.com/a/14933880/11635 est hautement spéculatif. Si je le pouvais, je donnerais un -1 pour la duplication et un -1 pour la spéculation / programmation par coïncidence. L'arrosage GC.Collectest a) juste un mauvais conseil et b) n'est pas une cause générale suffisamment commune de dir verrouillés pour mériter d'être inclus ici. Choisissez simplement l'un des autres et ne semez pas plus de confusion dans l'esprit des lecteurs innocents
Ruben Bartelink
3
Utilisez GC.WaitForPendingFinalizers (); après GC.Collect (); cela fonctionnera comme prévu.
Heiner
Pas sûr, non testé, mais peut-être mieux serait de faire quelque chose avec une usingdéclaration, alors: using (DirectoryInfo di = new DirectoryInfo(@"c:\MyDir")) { for (int attempts = 0; attempts < 10; attempts++) { try { if (di.Exists(folder)) { Directory.Delete(folder, true); } return; } catch (IOException e) { Thread.Sleep(1000); } } }
vapcguy
-3

ajouter vrai dans le deuxième paramètre.

Directory.Delete(path, true);

Cela supprimera tout.

Santiago Medina Chaverra
la source
1
Directory.Delete (chemin, vrai); était la question d'origine
Pisu