# Datei kann nicht verwendet werden



## CopWorker (20. August 2019)

Hallo zusammen, 

ich verwende die Klasse "File" aus "System.IO".
Mit folgender Syntax erstelle ich eine Datei:

```
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


----------



## Spyke (21. August 2019)

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 (21. August 2019)

CopWorker hat gesagt.:


> 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:

```
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:


StreamWriter Constructor (System.IO)
Create File If File Does Not Exist
*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!


----------



## Spyke (22. August 2019)

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.


----------



## CopWorker (22. August 2019)

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. 

```
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 (22. August 2019)

Spyke hat gesagt.:


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



Spyke hat gesagt.:


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



Spyke hat gesagt.:


> immer besser wenn möglich das selbst abzuprüfen.


Nein, weil die Prüfung in Euren Codes falsch ist. Sie erlaubt Race Conditions.



CopWorker hat gesagt.:


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


----------



## CopWorker (22. August 2019)

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 (22. August 2019)

CopWorker hat gesagt.:


> 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:

```
File.Open(strRet, FileMode.OpenOrCreate).Dispose()
```

Vorteile:

Frei von Race Conditions (eigentlich ausreichend als einziger Vorteil)
Noch kürzer und lesbarer als `if (exists) ...`



CopWorker hat gesagt.:


> 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:

```
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 
	
	
	



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


----------



## Spyke (22. August 2019)

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 (22. August 2019)

Spyke hat gesagt.:


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



Spyke hat gesagt.:


> 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


----------

