Datei kann nicht verwendet werden


#1
Hallo zusammen,

ich verwende die Klasse "File" aus "System.IO".
Mit folgender Syntax erstelle ich eine Datei:
C#:
if (!File.Exists(strFilePath))
    File.Create(strFilePath);
Die Datei kann ich im Explorer sehen.
Beim Versuch diese zu öffnen wird der Zugriff allerdings verweigert. (Siehe Anhang: PostCreateFile.PNG)
Auch kann mein Programm im anschließenden Verlauf nicht auf diese Datei zugreifen.

Reicht die Funktion "File.Exists(...) alleine nicht mehr aus?
Ich habe in der Vergangenheit doch schon hunderte Dateien erzeugt und anschließend verwendet.
Muss die erzeugte Datei nicht irgendwie freigegeben werden?

Jede Antwort zählt.
Vielen Dank für Eure Hilfe im Voraus.
Grüße von CopWorker
 

Anhänge

#2
File.Create liefert dir einen Stream zurück, diesen musst du zuerst disposen/closen, ansonsten ist die Datei für anderen Anwendungen gesperrt.
Auch für deine eigene Anwendung außer du würdest direkt mit dem zurück gegebenem Stream weiterarbeiten.

Sprich verwende direkt den zurückgegebenen Stream oder schließe diesen zuerst.
 

ComFreek

Mod | @comfreek
Moderator
#3
if (!File.Exists(strFilePath)) File.Create(strFilePath);
Warum prüfst du zuerst auf Existenz? In den allermeisten Fällen ist dieses Pattern von Exists und Create eben wegen Race Conditions falsch. Erstelle einfach direkt die Datei -- ggf. mit entsprechenden Flags, dass ein Fehler zurückgeworden wird, wenn sie schon existiert.

Ich habe mal ein bisschen im Internet gesucht. Ganz so einfach mit nur einem Flag geht's nicht, aber so geht es:
C#:
try {
  using (StreamWriter sw = new StreamWriter(File.Open(strFilePath, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write))) {
    // ...
  }
}
catch (IOException e) {
  // handle
}
Falls die Datei schon existiert, bekommst du eine IOException, die du mit catch abfangen könntest.

Quellen:

Edit: Es ist schon ein bisschen unglaublich, wie viele hochvotierte Antworten es auf StackOverflow gibt, die diese Race Condition enthalten. Ich habe gerade 16 downvoted!
 
Zuletzt bearbeitet:
#4
ComFreek da muss ich wiedersprechen.

Die Prüfung von Exists finde ich hier richtig.
Warum exception auslösen wenns mans ganz eifnach prüfen kann?
Vorallem sind Exceptions auch performance fresser, immer besser wenn möglich das selbst abzuprüfen.
Einfach krachen lassen nur wenn nicht anders geht.

Natürlich sollte ein try catch drum, aber nicht einfach so knallen lassen.
 
#5
Hallo Spyke,

so sehe ich das auch.
Da ich in die Datei in dieser Routine nichts reinschreiben will brauche ich
auch den StreamWriter nicht zu benutzen.

Ich hab´s jetzt einfach so gemacht.
C#:
if (!File.Exists(strRet))
     File.Create(strRet).Close();
Funktioniert ganz ordentlich. Es tut was es soll.

Trotzdem vielen Dank an alle.
Gruß von
CopWorker
 

ComFreek

Mod | @comfreek
Moderator
#6
Warum exception auslösen wenns mans ganz eifnach prüfen kann?
Weil Eure Lösung Race Conditions erlaubt! Wenn die Datei nämlich nach dem Checken der IF-Bedingung und vor dem File.Create (extern) erstellt wird, dann überschreibt ihr sie einfach.
Es gibt also die Chance, dass euer Code einfach eine Datei überschreibt.

Vorallem sind Exceptions auch performance fresser
@CopWorker hat nicht genannt, wo der Code aufgerufen wird. Wenn der Code z. B. nur sehr selten aufgerufen wird (ich werfe mal < 10 in den Raum), dann wird der Performanzunterscheid wahrscheinlich kleiner als im Millisekundenbereich sein.

immer besser wenn möglich das selbst abzuprüfen.
Nein, weil die Prüfung in Euren Codes falsch ist. Sie erlaubt Race Conditions.

Funktioniert ganz ordentlich. Es tut was es soll.
Es funktioniert, bis du die Race Condition erlebst. Wenn du Pech hast, passiert das als Teil eines viel größeren programmierten Systems und du fragst dich, warum zur Hölle die eine Datei einfach so gelöscht werden konnte. Race Conditions zu debuggen ist sehr schwierig, eben weil sie nicht so einfach reproduzierbar sind. Auch sie im Code als Mensch zu erkennen ist sehr schwierig. Glücklicherweise ist if (exists) do file IO eine klassische Race Condition, die man noch schnell erkennen kann, wenn man sie kennt.
 
#7
Hallo ComFreek,

Diese Abfrage wird nur einmal kurz nach dem Programmstart gestellt.
Die Datei darf auf keinen Fall überschrieben werden wenn sie bereits existiert.
Da komme Fehlermeldungen rein die ich während der Laufzeit generiert.
Eine Art Logfile.

mfG.
CopWorker
 

ComFreek

Mod | @comfreek
Moderator
#8
Da ich in die Datei in dieser Routine nichts reinschreiben will brauche ich auch den StreamWriter nicht zu benutzen.
Dann geht's noch einfacher und auch ohne Exception:
C#:
File.Open(strRet, FileMode.OpenOrCreate).Dispose()
Vorteile:
  • Frei von Race Conditions (eigentlich ausreichend als einziger Vorteil)
  • Noch kürzer und lesbarer als if (exists) ...
Da komme Fehlermeldungen rein die ich während der Laufzeit generiert.
Eine Art Logfile.
Obige Lösungen schließen die Datei immer sofort. Du kannst auch während der Programmausführung einen einzigen FileStream offen halten:
C#:
FileStream log = File.Open(strRet, FileMode.Append, FileAccess.Write);
Wenn du nun auf fs schreibst, fügst du immer am Ende hinzu ("append"). Falls die Datei noch nicht existierte, so wird sie erstellt. Beachte, dass die Aktion im letzten Satz atomar geschieht! Dieser Satz ist *nicht* synonym zu if (exists) ...! Er ist moralisch synonym zu
C#:
FileStream fs;
lockAllFileSystemAccess(); // imaginary function I just made up
if (exists) {
  // just open file into fs
}
else {
  // create and open file into fs
}
unlockAllFileSystemAccess();
Natürlich wird nicht das ganze Dateisystem gesperrt, sondern es wird ein wenig ausgeklügelter in der Windows API und in der Dateisystem API vorgegangen.

Möglicherweise möchtest du für das fs-Objekt noch regelmäßig Flush oder FlushAsync aufrufen oder die Write Buffergröße verringern. Denn sonst wenn dein Programm mitten drin abstürzt, sind vermeintlich in fs geschriebene Logzeilen noch im Buffer, aber nicht in die Logdatei rausgeschrieben.
 
#9
ok ich hab jetzt nicht geschaut was genau die Create Methode macht, hätte jetzt gedacht diese würde eine Exception schmeißen wenn die Datei plötzlich da ist und dies würde nochmals mit nem try catch abgesichert.

Im Grunde genommen kann man sagen es kommt auf den Anwedungsfall drauf an und aufs entsprechende Fehlerhandling.

Von Hause aus File.Exists ausschließen würd ich aber nicht, so klangs bei mir, kommt auf den Anwendungsfall drauf an.
 

ComFreek

Mod | @comfreek
Moderator
#10
ok ich hab jetzt nicht geschaut was genau die Create Methode macht, hätte jetzt gedacht diese würde eine Exception schmeißen wenn die Datei plötzlich da ist und dies würde nochmals mit nem try catch abgesichert.
Wenn du das Flag FileMode.CreateNew übergibst, bekommst du auch eine Exception, wenn die Datei schon existiert.

Im Grunde genommen kann man sagen es kommt auf den Anwedungsfall drauf an und aufs entsprechende Fehlerhandling.
Ja, das kann ich so unterschreiben. Ich würde aber hinzufügen, dass in den allermeisten Fällen, die ich so erlebt habe bisher, Race Conditions nicht erwünscht sind :)