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?

2voto

Douglas Leeder Punkte 50423

Ist es möglich, dass Sie eine Race Condition haben, bei der ein anderer Thread oder Prozess Dateien zum Verzeichnis hinzufügt:

Die Reihenfolge wäre wie folgt:

Löschvorgang A:

  1. Leeren Sie das Verzeichnis
  2. Löschen Sie das (nun leere) Verzeichnis.

Wenn jemand anderes eine Datei zwischen 1 und 2 hinzufügt, dann würde vielleicht 2 die aufgeführte Ausnahme auslösen?

1voto

Shaun Punkte 581

Ich hatte das gleiche Problem mit Windows Workflow Foundation auf einem Build-Server mit TFS2012. Intern rief der Workflow Directory.Delete() auf, wobei das Rekursiv-Flag auf true gesetzt war. In unserem Fall scheint es netzwerkbedingt zu sein.

Wir löschten einen Binärordner auf einer Netzwerkfreigabe, bevor wir ihn neu erstellten und mit den neuesten Binärdateien füllten. Jeder zweite Build schlug fehl. Beim Öffnen des Übergabeordners nach einem fehlgeschlagenen Build war der Ordner leer, was darauf hindeutet, dass jeder Aspekt des Directory.Delete()-Aufrufs erfolgreich war, mit Ausnahme des Löschens des eigentlichen Verzeichnisses.

Das Problem scheint durch die asynchrone Natur der Netzwerk-Dateikommunikation verursacht zu werden. Der Build-Server wies den Dateiserver an, alle Dateien zu löschen, und der Dateiserver meldete, dass er dies getan hatte, obwohl er noch nicht ganz fertig war. Dann forderte der Build-Server die Löschung des Verzeichnisses an, und der Dateiserver lehnte die Anforderung ab, da er die Löschung der Dateien noch nicht vollständig abgeschlossen hatte.

In unserem Fall gibt es zwei mögliche Lösungen:

  • Aufbau des rekursiven Löschvorgangs in unserem eigenen Code mit Verzögerungen und Überprüfungen zwischen den einzelnen Schritten
  • Wiederholung von bis zu X Mal nach einer IOException, mit einer Verzögerung vor dem nächsten Versuch

Die letztere Methode ist schnell und schmutzig, scheint aber zu funktionieren.

1voto

Roman Punkte 1816

Dies ist zurückzuführen auf FileChangesNotifications.

Das passiert seit ASP.NET 2.0. Wenn Sie einen Ordner innerhalb einer Anwendung löschen, wird wird neu gestartet . Sie können es selbst sehen, indem Sie ASP.NET Zustandsüberwachung .

Fügen Sie einfach diesen Code in Ihre web.config/configuration/system.web ein:

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

Danach besuchen Sie Windows Log -> Application . Was ist hier los?

Wenn Sie einen Ordner löschen, sollte es einen Unterordner geben, Delete(path, true) löscht zuerst den Unterordner. Das reicht aus, damit FileChangesMonitor von der Entfernung erfährt und Ihre Anwendung herunterfährt. In der Zwischenzeit ist Ihr Hauptverzeichnis noch nicht gelöscht. Dies ist das Ereignis aus Log:

enter image description here

Delete() seine Arbeit nicht beendet hat und weil die Anwendung heruntergefahren wird, löst sie eine Ausnahme aus:

enter image description here

Wenn Sie keine Unterordner haben in einem Ordner, den Sie löschen, löscht Delete() einfach alle Dateien und den Ordner, die Anwendung wird auch neu gestartet, aber Sie keine Ausnahmen erhalten denn der Neustart der Anwendung unterbricht nichts. Dennoch gehen alle laufenden Sitzungen verloren, die App reagiert beim Neustart nicht auf Anfragen usw.

Was nun?

Es gibt einige Umgehungsmöglichkeiten und Optimierungen, um dieses Verhalten zu deaktivieren, Verzeichnis Junction , Ausschalten von FCN mit der Registry , Anhalten von FileChangesMonitor mit Reflection (da es keine exponierte Methode gibt) aber sie scheinen nicht alle richtig zu sein, denn der FCN ist nicht ohne Grund da. Er kümmert sich um Struktur Ihrer Anwendung was nicht der Fall ist Struktur Ihrer Daten . Die kurze Antwort lautet: Legen Sie die Ordner, die Sie löschen möchten, außerhalb Ihrer Anwendung ab. FileChangesMonitor wird keine Benachrichtigungen erhalten und Ihre Anwendung wird nicht jedes Mal neu gestartet werden. Sie werden keine Ausnahmen erhalten. Um sie vom Web aus sichtbar zu machen, gibt es zwei Möglichkeiten:

  1. Erstellen Sie einen Controller, der eingehende Anrufe verarbeitet und dann Dateien zurückliefert, indem er aus einem Ordner außerhalb einer Anwendung (außerhalb von wwwroot) liest.

  2. Wenn Ihr Projekt groß ist und die Leistung im Vordergrund steht, sollten Sie einen separaten kleinen und schnellen Webserver für die Bereitstellung statischer Inhalte einrichten. Auf diese Weise überlassen Sie dem IIS seine spezielle Aufgabe. Dieser könnte auf demselben Rechner (mongoose für Windows) oder einem anderen Rechner (nginx für Linux) laufen. Die gute Nachricht ist, dass Sie für die Einrichtung eines Servers für statische Inhalte unter Linux keine zusätzliche Microsoft-Lizenz bezahlen müssen.

Ich hoffe, das hilft.

1voto

GrokSrc Punkte 2698

Ich hatte heute dieses Problem. Es trat auf, weil ich den Windows-Explorer für das zu löschende Verzeichnis geöffnet hatte, wodurch der rekursive Aufruf fehlschlug und somit die IOException auftrat. Stellen Sie sicher, dass keine Handles für das Verzeichnis geöffnet sind.

Außerdem ist MSDN klar, dass Sie Ihre eigene Aufzählung nicht schreiben müssen: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx

1voto

HostageBrain Punkte 224

Dieses Problem kann unter Windows auftreten, wenn sich Dateien in einem Verzeichnis (oder in einem Unterverzeichnis) befinden, deren Pfadlänge mehr als 260 Zeichen beträgt.

In solchen Fällen müssen Sie Folgendes löschen \\\\?\C:\mydir 代わりに C:\mydir . Über die 260 Symbole Grenze können Sie lesen aquí .

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