Ich habe einen Code und wenn er ausgeführt wird, wirft er einen IOException
und sagt das
Der Prozess kann nicht auf die Datei 'Dateiname' zugreifen, da sie von einem anderen Prozess verwendet wird
Was bedeutet das und was kann ich dagegen tun?
c#
.net
language-agnostic
ioexception
Adriano Repetti
quelle
quelle
Antworten:
Was ist die Ursache?
Die Fehlermeldung ist ziemlich klar: Sie versuchen, auf eine Datei zuzugreifen, und sie ist nicht zugänglich, weil ein anderer Prozess (oder sogar derselbe Prozess) etwas damit macht (und keine Freigabe zuließ).
Debuggen
Abhängig von Ihrem spezifischen Szenario kann es ziemlich einfach zu lösen (oder ziemlich schwer zu verstehen) sein. Mal sehen.
Ihr Prozess ist der einzige, der auf diese Datei
zugreift. Sie sind sicher, dass der andere Prozess Ihr eigener Prozess ist. Wenn Sie wissen, dass Sie diese Datei in einem anderen Teil Ihres Programms öffnen, müssen Sie zunächst überprüfen, ob Sie das Dateihandle nach jeder Verwendung ordnungsgemäß schließen. Hier ist ein Beispiel für Code mit diesem Fehler:
Glücklicherweise
FileStream
implementiertIDisposable
, so ist es einfach, Ihren gesamten Code in eineusing
Anweisung zu packen :Dieses Muster stellt auch sicher, dass die Datei im Falle von Ausnahmen nicht geöffnet bleibt (dies kann der Grund sein, warum die Datei verwendet wird: Es ist ein Fehler aufgetreten, und niemand hat sie geschlossen; ein Beispiel finden Sie in diesem Beitrag ).
Wenn alles in Ordnung zu sein scheint (Sie sind sicher, dass Sie jede geöffnete Datei auch in Ausnahmefällen immer schließen) und Sie mehrere Arbeitsthreads haben, haben Sie zwei Möglichkeiten: Überarbeiten Sie Ihren Code, um den Dateizugriff zu serialisieren (nicht immer machbar und nicht immer gesucht) oder wenden Sie ein Wiederholungsmuster an . Es ist ein ziemlich häufiges Muster für E / A-Vorgänge: Sie versuchen, etwas zu tun, und im Fehlerfall warten Sie und versuchen es erneut (haben Sie sich gefragt, warum beispielsweise Windows Shell einige Zeit benötigt, um Sie darüber zu informieren, dass eine Datei verwendet wird? und kann nicht gelöscht werden?). In C # ist die Implementierung ziemlich einfach (siehe auch bessere Beispiele für Festplatten-E / A , Netzwerk und Datenbankzugriff ).
Bitte beachten Sie einen häufigen Fehler, den wir sehr oft bei StackOverflow sehen:
In diesem Fall
ReadAllText()
schlägt dies fehl, da die Datei verwendet wird (File.Open()
in der vorherigen Zeile). Das vorherige Öffnen der Datei ist nicht nur unnötig, sondern auch falsch. Das gleiche gilt für alleFile
Funktionen, die keinen Rückgriff Sie arbeiten mit an der Datei:File.ReadAllText()
,File.WriteAllText()
,File.ReadAllLines()
,File.WriteAllLines()
und andere (wieFile.AppendAllXyz()
Funktionen) werden alle öffnen und schließen Sie die Datei selbst.Ihr Prozess ist nicht der einzige, der auf diese Datei zugreift.
Wenn Ihr Prozess nicht der einzige ist, der auf diese Datei zugreift, kann die Interaktion schwieriger sein. Ein Wiederholungsmuster hilft (wenn die Datei nicht von jemand anderem geöffnet werden sollte, aber dies ist der Fall, benötigen Sie ein Dienstprogramm wie Process Explorer, um zu überprüfen, wer was tut ).
Möglichkeiten zu vermeiden
Verwenden Sie gegebenenfalls immer using- Anweisungen, um Dateien zu öffnen. Wie im vorherigen Absatz erwähnt, hilft es Ihnen aktiv, viele häufige Fehler zu vermeiden (in diesem Beitrag finden Sie ein Beispiel, wie Sie es nicht verwenden können ).
Versuchen Sie nach Möglichkeit zu entscheiden, wem der Zugriff auf eine bestimmte Datei gehört, und zentralisieren Sie den Zugriff mithilfe einiger bekannter Methoden. Wenn Sie beispielsweise eine Datendatei haben, in der Ihr Programm liest und schreibt, sollten Sie den gesamten E / A-Code in einer einzigen Klasse einschließen. Dies erleichtert das Debuggen (da Sie dort immer einen Haltepunkt setzen und sehen können, wer was tut) und ist ein Synchronisationspunkt (falls erforderlich) für den Mehrfachzugriff.
Vergessen Sie nicht, dass E / A-Vorgänge immer fehlschlagen können. Ein häufiges Beispiel ist Folgendes:
Wenn jemand die Datei nach,
File.Exists()
aber vorher löschtFile.Delete()
, wird sieIOException
an einen Ort geworfen, an dem Sie sich möglicherweise fälschlicherweise sicher fühlen.Wenden Sie nach Möglichkeit ein Wiederholungsmuster an. Wenn Sie es verwenden
FileSystemWatcher
, sollten Sie die Aktion verschieben (da Sie benachrichtigt werden, eine Anwendung jedoch möglicherweise weiterhin ausschließlich mit dieser Datei arbeitet).Erweiterte Szenarien
Es ist nicht immer so einfach, daher müssen Sie möglicherweise den Zugriff für andere Personen freigeben. Wenn Sie beispielsweise von Anfang an lesen und bis zum Ende schreiben, haben Sie mindestens zwei Möglichkeiten.
1) teilen Sie das gleiche
FileStream
mit den richtigen Synchronisationsfunktionen (weil es nicht threadsicher ist ). Ein Beispiel finden Sie in diesem und diesen Beiträgen.2) Verwenden Sie die
FileShare
Aufzählung, um das Betriebssystem anzuweisen, anderen Prozessen (oder anderen Teilen Ihres eigenen Prozesses) den gleichzeitigen Zugriff auf dieselbe Datei zu ermöglichen.In diesem Beispiel habe ich gezeigt, wie eine Datei zum Schreiben geöffnet und zum Lesen freigegeben wird. Bitte beachten Sie, dass beim Lesen und Schreiben von Überschneidungen undefinierte oder ungültige Daten entstehen. Es ist eine Situation, die beim Lesen behandelt werden muss. Beachten Sie auch, dass dies keinen Zugriff auf den
stream
Thread sicher macht, sodass dieses Objekt nicht für mehrere Threads freigegeben werden kann, es sei denn, der Zugriff ist irgendwie synchronisiert (siehe vorherige Links). Andere Freigabeoptionen sind verfügbar und eröffnen komplexere Szenarien. Weitere Informationen finden Sie in MSDN .Im Allgemeinen können N Prozesse alle zusammen aus derselben Datei lesen, aber nur einer sollte schreiben. In einem kontrollierten Szenario können Sie sogar gleichzeitige Schriften aktivieren, dies kann jedoch nicht in wenigen Textabschnitten in dieser Antwort verallgemeinert werden.
Ist es möglich, eine von einem anderen Prozess verwendete Datei zu entsperren ? Es ist nicht immer sicher und nicht so einfach, aber ja, es ist möglich .
quelle
File.Create(path)
, sollten Sie sie.Close()
am Ende hinzufügen , bevor Sie darauf schreiben. Es gibt solche Fallstricke, zusätzlich zu denusing
Anweisungen zum Schreiben der Dateien und zum anschließenden Löschen. Sie sollten den Code in Ihrer Frage veröffentlichen, wie Sie Ihre Datei erstellen und löschen. Aber wahrscheinlich stimmt mit etwas oben Erwähntem überein.Directory.SetCreationTimeUTC()
, schlägt jedoch fehl, wenn der Datei-Explorer geöffnet ist und behauptet, dass ein anderer Prozess auf das Verzeichnis zugreift. Wie soll ich mit dieser Situation umgehen?Die Verwendung von FileShare hat mein Problem beim Öffnen von Dateien behoben, auch wenn diese von einem anderen Prozess geöffnet wurden.
quelle
Hatte ein Problem beim Hochladen eines Bildes und konnte es nicht löschen und fand eine Lösung. Viel Glück und Viel Spaß
quelle
Ich habe diesen Fehler erhalten, weil ich File.Move zu einem Dateipfad ohne Dateinamen ausgeführt habe. Sie müssen den vollständigen Pfad im Ziel angeben.
quelle
Der Fehler zeigt an, dass ein anderer Prozess versucht, auf die Datei zuzugreifen. Vielleicht haben Sie oder jemand anderes es geöffnet, während Sie versuchen, darauf zu schreiben. "Lesen" oder "Kopieren" verursacht dies normalerweise nicht, aber das Schreiben oder Aufrufen von "Löschen" würde dies bewirken.
Es gibt einige grundlegende Dinge, um dies zu vermeiden, wie andere Antworten erwähnt haben:
In
FileStream
Betrieb, legen Sie sie in einemusing
Block mit einemFileShare.ReadWrite
Zugriffsmodus.Beispielsweise:
Beachten Sie, dass
FileAccess.ReadWrite
dies bei Verwendung nicht möglich istFileMode.Append
.Ich bin auf dieses Problem gestoßen, als ich einen Eingabestream verwendet habe, um zu tun,
File.SaveAs
wann die Datei verwendet wurde. In meinem Fall musste ich es eigentlich gar nicht im Dateisystem speichern, also habe ich es letztendlich nur entfernt, aber ich hätte wahrscheinlich versuchen können, einen FileStream in einerusing
Anweisung mit zu erstellenFileAccess.ReadWrite
, ähnlich wie der Code über.Speichern Sie Ihre Daten als eine andere Datei und löschen Sie die alte Datei, wenn festgestellt wird, dass sie nicht mehr verwendet wird. Anschließend können Sie die erfolgreich gespeicherte Datei in den Namen der ursprünglichen Datei umbenennen. Wie Sie testen, ob die Datei verwendet wird, erfahren Sie über die
Zeile in meinem Code unten, und könnte in einem Windows-Dienst in einer Schleife erfolgen, wenn Sie eine bestimmte Datei haben, die Sie regelmäßig ansehen und löschen möchten, wenn Sie sie ersetzen möchten. Wenn Sie nicht immer dieselbe Datei haben, kann eine Textdatei oder Datenbanktabelle aktualisiert werden, die der Dienst immer auf Dateinamen überprüft und dann diese Prüfung auf Prozesse durchführt und anschließend die Prozessabbrüche und -löschungen darauf durchführt, wie ich beschreibe in der nächsten Option. Beachten Sie, dass Sie einen Benutzernamen und ein Kennwort für das Konto benötigen, die auf dem angegebenen Computer über Administratorrechte verfügen, um das Löschen und Beenden von Prozessen durchführen zu können.
Wenn Sie nicht wissen, ob eine Datei beim Speichern verwendet wird, können Sie vor dem Speichern alle Prozesse schließen, die sie möglicherweise verwenden, z. B. Word, wenn es sich um ein Word-Dokument handelt.
Wenn es lokal ist, können Sie dies tun:
Wenn es remote ist, können Sie dies tun:
wo
txtUserName
ist in Form vonDOMAIN\user
.Angenommen, Sie kennen den Prozessnamen, der die Datei sperrt, nicht. Dann können Sie dies tun:
Beachten Sie, dass
file
der UNC - Pfad sein muss:\\computer\share\yourdoc.docx
um dasProcess
herauszufinden, was Computer ist es auf und ump.MachineName
gültig zu sein.Nachfolgend finden Sie die Klasse, die diese Funktionen verwenden und für die ein Verweis hinzugefügt werden muss
System.Management
. Der Code wurde ursprünglich von Eric J geschrieben :quelle
Wie andere Antworten in diesem Thread gezeigt haben, müssen Sie den Code sorgfältig untersuchen, um diesen Fehler zu beheben und zu verstehen, wo die Datei gesperrt wird.
In meinem Fall habe ich die Datei als E-Mail-Anhang gesendet, bevor ich den Verschiebevorgang ausgeführt habe.
Daher wurde die Datei für einige Sekunden gesperrt, bis der SMTP-Client das Senden der E-Mail beendet hatte.
Die Lösung, die ich gewählt habe, bestand darin , zuerst die Datei zu verschieben und dann die E-Mail zu senden. Dies löste das Problem für mich.
Eine andere mögliche Lösung, auf die Hudson bereits hingewiesen hat, wäre gewesen, das Objekt nach der Verwendung zu entsorgen.
quelle
File.Move()
wird, funktioniert sie nicht und gibt den gleichen Fehler aus. Wenn Sie einer E-Mail nur eine Datei hinzufügen, glaube ich nicht, dass sie bei der Verwendung während desAttachments.Add()
Vorgangs fehlerhaft ist, da dies nur ein Kopiervorgang ist. Wenn dies aus irgendeinem Grund der Fall ist, können Sie es in ein temporäres Verzeichnis kopieren, die Kopie anhängen und die kopierte Datei anschließend löschen. Aber ich denke nicht, dass, wenn das OP eine Datei ändern und diese verwenden möchte, diese Art von Lösung (für die Sie nicht den Code angezeigt haben, sondern nur den anhängenden Teil) funktionieren würde..Dispose()
ist immer eine gute Idee, aber hier nicht relevant, es sei denn, die Datei wurde in einer vorherigen Operation geöffnet.Ich hatte das folgende Szenario, das den gleichen Fehler verursachte:
Die meisten Dateien waren klein, einige jedoch groß. Der Versuch, diese zu löschen, führte zu dem Fehler, dass nicht auf Dateien zugegriffen werden kann.
Es war nicht leicht zu finden, die Lösung war jedoch so einfach wie das Warten "auf die Ausführung der Aufgabe":
quelle
Mein unten stehender Code löst dieses Problem, aber ich schlage vor. Zunächst müssen Sie verstehen, was dieses Problem verursacht, und die Lösung ausprobieren, die Sie durch Ändern des Codes finden können
Ich kann einen anderen Weg zur Lösung dieses Problems angeben, aber eine bessere Lösung besteht darin, Ihre Codierungsstruktur zu überprüfen und zu analysieren, was dies bewirkt. Wenn Sie keine Lösung finden, können Sie diesen Code unten verwenden
quelle
GC.*()
Sie wahrscheinlich andere Probleme mit Ihrem Code. 2) Die Nachricht ist lokalisiert und zerbrechlich . Verwenden Sie stattdessen das HRESULT. 3) Vielleicht möchten Sie mit schlafenTask.Delay()
(und zehn Sekunden sind in vielen Fällen irgendwie zu lang). 4) Sie haben keine Exit-Bedingung: Dieser Code könnte für immer hängen bleiben. 5) Sie brauchengoto
hier definitiv nicht . 6) FangenException
ist normalerweise eine schlechte Idee, in diesem Fall auch, weil ... 6) Wenn etwas anderes passiert, schlucken Sie den Fehler.GC.Collect()
war der Umgang mit einigen COM-Objekten.