1. Einführung
Wenn du mit Dateien über FileStream oder andere Stream-Klassen arbeitest, ist es super wichtig, vorher zu checken, was genau mit der Datei passiert, wenn du sie öffnest. Oft gibt’s die Situation, dass die Datei schon existiert und du entweder neue Daten anhängen willst, ohne das Alte zu verlieren, oder die Datei komplett überschreiben möchtest. Andererseits gibt’s Momente, wo die Datei noch gar nicht existiert und du sie einfach nur lesen willst, ohne aus Versehen eine leere Datei zu erzeugen.
Zum Beispiel: Wenn du ein Notizbuch für tägliche Einträge schreibst, willst du neue Notizen ans Ende einer bestehenden Datei anhängen und alles Alte behalten. Das heißt, du musst die Datei im Append-Modus öffnen. In einem anderen Fall – sagen wir, du hast eine Logdatei, die bei jedem App-Start neu angelegt werden soll, damit alte Daten nicht stören. Hier solltest du die Datei so öffnen, dass sie beim Öffnen geleert oder neu erstellt wird, falls sie nicht existiert. Und wenn du einfach nur eine bestehende Datei lesen willst, willst du sicherstellen, dass keine neue Datei angelegt wird, falls sie fehlt – sonst hast du plötzlich eine leere Datei, wo keine sein sollte.
All diese verschiedenen Situationen – Anhängen, Überschreiben, Lesen ohne Erstellen – werden in C# über spezielle Dateiöffnungsmodi geregelt, die du mit dem Enum System.IO.FileMode einstellst. Jeder Modus steuert das Verhalten beim Öffnen oder Erstellen der Datei und gibt dir die volle Kontrolle darüber, was beim Zugriff auf die Datei passiert.
2. Das Enum FileMode – alle Varianten ganz easy erklärt
Hier sind die wichtigsten Werte vom Enum FileMode:
| Wert | Beschreibung | Verhalten bei existierender Datei | Verhalten bei fehlender Datei |
|---|---|---|---|
|
Erstellt eine neue Datei. Wenn die Datei schon existiert – wirft eine Exception | Fehler | Ok, Datei wird erstellt |
|
Erstellt eine neue Datei wenn sie nicht existiert, oder überschreibt die bestehende | Überschreibt | Ok, erstellt |
|
Öffnet eine bestehende Datei. Wenn die Datei fehlt – Exception | Ok, öffnet | Fehler |
|
Öffnet, wenn vorhanden, sonst wird eine neue erstellt | Ok, öffnet | Ok, erstellt |
|
Öffnet eine bestehende Datei und setzt ihre Länge auf 0 (Inhalt wird gelöscht) | Ok, Datei wird geleert | Fehler |
|
Öffnet die Datei zum Anhängen ans Ende, wenn sie fehlt – wird sie neu erstellt | Ok, hängt ans Ende an | Ok, erstellt |
Illustration: Verhaltensszenarien
flowchart TD
Start[Start]
A{Datei existiert?}
B1[Zum Anhängen öffnen]
B2[Neue Datei erstellen]
B3[Datei überschreiben]
B4[Datei öffnen]
B5[Fehler: Datei nicht gefunden]
B6[Fehler: Datei existiert schon]
Start --> A
A --Append, OpenOrCreate--> B1
A --Create, Truncate--> B3
A --Open, Truncate--> B4
A --CreateNew--> B6
A --Create, OpenOrCreate, Append--> B2
A --Open, Truncate--> B5
3. Beispiele für das Öffnen von Dateien in verschiedenen Modi
Lass uns das Ganze mal praktisch ausprobieren mit unserer kleinen Beispiel-App, die wir im Kurs entwickeln. Stell dir vor, wir haben eine Textdatei, in die wir Grüße und das aktuelle Datum schreiben. Wir schauen uns drei typische Szenarien an:
- A. Neue Datei erstellen (CreateNew)
- B. Datei überschreiben (Create)
- C. Zeilen ans Ende der Datei anhängen (Append)
Neue Datei erstellen (FileMode.CreateNew)
Wenn die Datei schon existiert, garantiert dieser Modus, dass sie nicht nochmal erstellt wird: Das Programm wirft eine IOException. Das ist praktisch, wenn du keine Daten verlieren oder versehentlich fremde Dateien löschen willst.
using System;
using System.IO;
string filePath = "greeting.txt";
// Wir versuchen, eine neue Datei zu erstellen – wenn sie schon existiert, gibt’s eine Exception!
try
{
var stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
var writer = new StreamWriter(stream);
writer.WriteLine("Hallo! Das ist der erste Eintrag.");
writer.WriteLine($"Datum: {DateTime.Now}");
Console.WriteLine("Datei erfolgreich erstellt.");
writer.Close();
}
catch (IOException)
{
Console.WriteLine($"Datei '{filePath}' existiert schon! Wir überschreiben sie nicht.");
}
Wichtig: Wenn du diesen Code ein zweites Mal startest – dann greift der catch-Block und die Daten bleiben erhalten.
Datei überschreiben (FileMode.Create)
Dieser Modus ist kompromisslos: Wenn die Datei schon existiert, wird sie komplett geleert. Wenn nicht – wird einfach eine neue erstellt. Praktisch, wenn du immer "bei Null" anfangen willst. Zum Beispiel, um einen Bericht neu zu speichern.
using System;
using System.IO;
string filePath = "greeting.txt";
// Datei erstellen oder komplett überschreiben
var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write);
var writer = new StreamWriter(stream);
writer.WriteLine("Hallo! Ich habe die Datei komplett aktualisiert :)");
writer.WriteLine($"Aktualisiert: {DateTime.Now}");
Console.WriteLine("Datei erstellt oder überschrieben.");
writer.Close();
Starte diesen Code mehrmals – in der Datei stehen immer nur die letzten Zeilen. Alles Alte ist weg.
Ans Ende der Datei anhängen (FileMode.Append)
Super Modus für Logs, Event-Journale, Besucherlisten usw. Wenn die Datei fehlt – wird sie erstellt. Wenn sie existiert – werden die Daten ans Ende angehängt.
using System;
using System.IO;
string filePath = "greeting.txt";
// Neue Zeile ans Ende der Datei anhängen
var stream = new FileStream(filePath, FileMode.Append, FileAccess.Write);
var writer = new StreamWriter(stream);
writer.WriteLine($"Noch ein Gruß! Datum: {DateTime.Now}");
Console.WriteLine("Neue Zeile ans Ende der Datei angehängt.");
writer.Close();
Starte diesen Code ruhig mehrmals hintereinander. Die Datei wächst und jeder neue Eintrag landet ganz unten.
4. Welchen Dateiöffnungsmodus wählen? Praktische Tipps
Typische Alltagsszenarien:
- Logging: Fast immer Append verwenden. Logs durch Überschreiben zu verlieren ist der Albtraum jedes Admins und ein Geschenk für Bösewichte.
- Berichtsexport: Meist Create, damit der Ordner nicht mit alten Versionen zugemüllt wird.
- Datenexport, bei dem Datenverlust kritisch ist: Hier passt CreateNew. Wenn die Datei existiert – Fehler, nichts wird angerührt.
- Datei lesen: Hier brauchst du keinen Erstellmodus, nimm FileMode.Open – wenn die Datei fehlt, ist das ein Problem.
Beim C#-Coden nutzt man oft die statischen Methoden der File-Klasse, die intern schon den passenden Modus wählen. Zum Beispiel arbeitet File.AppendAllText immer mit Append, und File.WriteAllText mit Create.
5. Datei-Modi und typische Probleme
Ein paar fiese Stolperfallen:
Wenn du eine Datei mit FileMode.Create oder FileMode.Truncate öffnest, wird der komplette Inhalt gelöscht. Sei vorsichtig – versehentlicher Datenverlust passiert nicht nur Anfängern, sondern auch alten Hasen.
Wenn du versuchst, eine nicht existierende Datei mit FileMode.Open oder FileMode.Truncate zu öffnen, bekommst du eine FileNotFoundException. Check also immer vorher mit File.Exists(path), ob die Datei wirklich da ist.
Mit Append kannst du nur schreiben. Wenn du lesen und schreiben willst, nimm lieber andere Modi (OpenOrCreate + passenden FileAccess).
Beispiel: Lesen und Schreiben
Manchmal willst du lesen und schreiben (z.B. Bankkonto öffnen – einzahlen und Kontostand checken). Nimm FileMode.OpenOrCreate:
using System.IO;
string filePath = "balance.txt";
// Datei zum Lesen und Schreiben öffnen; wenn sie fehlt – erstellen
var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
// Hier kannst du lesen und schreiben
6. Nützliche Details
Dateiöffnungsmodi
graph TD
A[Datei anfordern] --> B[Modus wählen]
B --> C1[CreateNew] -->|Wenn Datei existiert| D1[Fehler]
C1 -->|Datei existiert nicht| E1[Erstellen]
B --> C2[Create] -->|Immer| F1[Erstellen/Überschreiben]
B --> C3[Open] -->|Datei existiert| G1[Öffnen]
C3 -->|Datei fehlt| D1
B --> C4[OpenOrCreate] -->|Datei existiert| G1
C4 -->|Datei fehlt| E1
B --> C5[Append] -->|Datei existiert| H1[Zum Anhängen öffnen]
C5 -->|Datei fehlt| E1
B --> C6[Truncate] -->|Datei existiert| I1[Leeren]
C6 -->|Datei fehlt| D1
Zusammenfassungstabelle zu Dateiöffnungsmodi
| FileMode | Datei existiert | Datei existiert NICHT | Datenzugriff | Löscht alten Inhalt? |
|---|---|---|---|---|
|
Exception | Erstellt neu | Schreiben | N/A |
|
Überschreibt | Erstellt neu | Schreiben | Ja |
|
Öffnet | Exception | Lesen/Schreiben | Nein |
|
Öffnet | Erstellt neu | Lesen/Schreiben | Nein |
|
Leert | Exception | Schreiben | Ja |
|
Zum Anhängen öffnen | Erstellt neu | Nur Schreiben | Nein (fügt hinzu) |
Vergleich mit High-Level-Methoden der File-Klasse
- File.WriteAllText(path, text) → nutzt intern FileMode.Create, also wird die alte Datei überschrieben.
- File.AppendAllText(path, text) → nutzt Append, alles wird ans Ende angehängt.
- File.ReadAllText(path) → öffnet die Datei zum Lesen (FileMode.Open).
Oft reichen diese Methoden, aber mit FileStream und explizitem Modus hast du die volle Kontrolle.
Besonderheiten je nach Betriebssystem
Viele Entwickler vergessen, dass unter Windows eine Datei, die von einem anderen Prozess zum Schreiben geöffnet ist, nicht nochmal geöffnet werden kann – der Zugriff führt zu einem Fehler. Deshalb ist es wichtig, den FileShare-Parameter richtig zu setzen, um den gemeinsamen Zugriff zu steuern (dazu gibt’s später noch mehr). Die Mechanismen für Locks und Rechte sind je nach Betriebssystem unterschiedlich, aber das Grundprinzip der Dateiöffnungsmodi bleibt überall gleich.
GO TO FULL VERSION