422 Stimmen

Verzeichnis kann nicht mit Directory.Delete(path, true) gelöscht werden

Ich verwende .NET 3.5 und versuche, ein Verzeichnis mit rekursiv zu löschen:

Directory.Delete(myPath, true);

Meines Erachtens sollte dies zu einem Fehler führen, wenn Dateien in Gebrauch sind oder ein Problem mit den Zugriffsrechten besteht, aber ansonsten sollten das Verzeichnis und sein gesamter Inhalt gelöscht werden.

Gelegentlich erhalte ich jedoch diese Meldung:

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)
    ...

Ich bin nicht überrascht, dass die Methode manchmal abbricht, aber ich bin überrascht, dass ich diese spezielle Meldung erhalte, wenn rekursiv wahr ist (ich wissen das Verzeichnis ist nicht leer.)

Gibt es einen Grund, warum ich dies anstelle von AccessViolationException sehen würde?

3voto

cdiggins Punkte 16400

Diese Antwort stützt sich auf: https://stackoverflow.com/a/1703799/184528 . Der Unterschied zu meinem Code ist, dass wir nur rekursiv viele Unterverzeichnisse und Dateien löschen, wenn ein Aufruf von Directory.Delete beim ersten Versuch fehlschlägt (was passieren kann, weil der Windows-Explorer ein Verzeichnis betrachtet).

    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);
        } 
    }

3voto

Rob Punkte 423

Wie bereits erwähnt, scheitert die "akzeptierte" Lösung an Reparse-Punkten. Es gibt eine viel kürzere Lösung, die die Funktionalität richtig repliziert:

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);
}

Ich weiß, dass es die später erwähnten Genehmigungsfälle nicht behandelt, aber es bietet in jeder Hinsicht VIEL BESSER die erwartete Funktionalität des Originals/Bestands Directory.Delete() - und auch mit viel weniger Code .

Sie können gefahrlos mit der Bearbeitung fortfahren, da das alte Verzeichnis aus dem Weg geräumt ist. ...selbst wenn sie nicht verschwunden sind, weil das "Dateisystem noch aufholt" (oder welche Ausrede MS auch immer für die Bereitstellung einer defekten Funktion vorgebracht hat) .

Wenn Sie wissen, dass Ihr Zielverzeichnis groß/tief ist, und nicht warten wollen (oder sich mit Ausnahmen herumärgern wollen), können Sie die letzte Zeile durch ersetzen:

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

Sie können weiterhin sicher arbeiten.

3voto

citykid Punkte 8762

Das rekursive Löschen von Verzeichnissen, bei dem keine Dateien gelöscht werden, ist sicherlich unerwartet. Meine Lösung für dieses Problem:

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

Ich habe Fälle erlebt, in denen dies geholfen hat, aber im Allgemeinen löscht Directory.Delete Dateien innerhalb von Verzeichnissen bei rekursiver Löschung, da dokumentiert in msdn .

Von Zeit zu Zeit begegnet mir dieses unregelmäßige Verhalten auch als Benutzer des Windows Explorer: Manchmal kann ich einen Ordner nicht löschen (es erscheint die unsinnige Meldung "Zugriff verweigert"), aber wenn ich nach unten gehe und die unteren Elemente lösche, kann ich auch die oberen Elemente löschen. Ich vermute also, dass der obige Code mit einer Anomalie des Betriebssystems zu tun hat - und nicht mit einem Problem der Basisklassenbibliothek.

2voto

nzrytmn Punkte 4812

Sie müssen keine zusätzliche Methode für die Rekursivität erstellen oder Dateien innerhalb eines Ordners extra löschen. Dies alles geschieht automatisch durch den Aufruf von

DirectoryInfo.Delete();

Details sind aquí .

So etwas funktioniert ganz gut:

  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
    }

Übergabe von true als Variable an die Löschmethode, werden auch Unterdateien und Unterordner mit Dateien gelöscht.

2voto

Demid Punkte 45

Ich habe einige Stunden damit verbracht, dieses Problem und andere Ausnahmen zu lösen, indem ich das Verzeichnis gelöscht habe. Dies ist meine Lösung

 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);
        }
    }

Dieser Code hat die kleine Verzögerung, die für meine Anwendung nicht wichtig ist. Aber Vorsicht, die Verzögerung kann ein Problem für Sie sein, wenn Sie eine Menge Unterverzeichnisse innerhalb des Verzeichnisses haben, das Sie löschen möchten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X