1. Die Klasse File: Einfachheit und Effizienz
Die Klasse System.IO.File verkörpert das Konzept "eine Operation – eine Methode". Sie bietet eine Reihe von High-Level-Methoden, die die komplexe Logik der Interaktion mit dem Betriebssystem kapseln, sodass du dich auf deine eigentliche Aufgabe konzentrieren kannst.
Was kann die Klasse File eigentlich?
- Text oder beliebige Binärdaten in eine Datei schreiben.
- Dateiinhalt lesen – komplett oder zeilenweise (bei Textdateien).
- Dateien kopieren, löschen und umbenennen.
- Existenz einer Datei an einem bestimmten Pfad prüfen.
- Mit Datei-Attributen arbeiten (z.B. Erstellungsdatum, Größe – über begleitende Klassen).
Warum ist das praktisch?
Alle Methoden von File sind statisch. Das heißt, du musst kein Objekt erstellen, sondern kannst einfach die gewünschte Methode aufrufen, zum Beispiel:
File.WriteAllText("data.txt", "Hallo, Datei!");
Dieser Stil erinnert sehr an die Arbeit mit der Klasse Console: alles ist einfach und verständlich, du musst nichts "erstellen" und brauchst dich nicht um Streams zu kümmern.
Wenn du ein universelles und bequemes Tool für die Arbeit mit Dateien zur Hand haben willst, ist die Klasse System.IO.File genau das Richtige. Sie bietet viele Methoden zum Lesen, Schreiben, Kopieren, Löschen und für andere grundlegende Dateioperationen – wie ein Schweizer Taschenmesser für das Dateisystem.
Wie benutzt man File?
Alle Methoden der Klasse File sind statisch, du musst also kein Objekt erstellen – einfach File.Irgendwas() schreiben. Das ist sehr ähnlich wie Console.WriteLine(), nur eben für Dateien.
string text = "Hallo, Welt!";
string path = "hello.txt";
// Text in Datei schreiben (überschreibt, falls Datei schon existiert!)
File.WriteAllText(path, text);
// Ganze Datei als String lesen
string readText = File.ReadAllText(path);
Console.WriteLine("Dateiinhalt: " + readText);
Lifehack: Wenn du zehnmal hintereinander ReadAllText und WriteAllText schreibst, machst du wahrscheinlich etwas falsch – diese Methoden sind super für einfache Szenarien und kleine Dateien.
Oft genutzte Methoden der Klasse File
| Methode | Beschreibung |
|---|---|
|
Prüft, ob eine Datei am angegebenen Pfad existiert |
|
Löscht eine Datei |
|
Kopiert eine Datei |
|
Verschiebt (oder benennt um) eine Datei |
|
Liest die ganze Datei als einen String |
|
Schreibt einen String in die Datei (überschreibt, falls sie existiert) |
|
Liest alle Zeilen der Datei in ein String-Array |
|
Schreibt ein String-Array in die Datei (jede Zeile einzeln) |
|
Liest alle Bytes der Datei in ein Byte-Array |
|
Schreibt ein Byte-Array in die Datei |
2. Textdateien schreiben und lesen
Schauen wir uns die meistgenutzten Methoden der Klasse File mit praktischen Beispielen an. Dafür brauchst du immer das using-Statement using System.IO; am Anfang deiner Datei.
using System;
using System.IO; // Unbedingt nötig für die File-Klasse
using System.Linq; // Kann für ReadLines gebraucht werden
Datei komplett lesen
Das ist eine der häufigsten Aufgaben: Textdaten in einer Datei speichern oder wieder einlesen.
Eine Zeile (oder den ganzen Text) in eine Datei schreiben: File.WriteAllText() Diese Methode erstellt eine neue Datei am angegebenen Pfad. Falls die Datei schon existiert, wird ihr Inhalt komplett mit dem neuen Text überschrieben.
string myFilePath = "notes.txt";
string textContent = "Heute ist ein großartiger Tag, um C# zu lernen.\nVergiss nicht, die Hausaufgaben zu machen.";
// Den ganzen Text in die Datei schreiben
File.WriteAllText(myFilePath, textContent);
Console.WriteLine($"Datei '{myFilePath}' wurde erfolgreich erstellt/überschrieben.");
Datei komplett als einen String lesen: File.ReadAllText() Diese Methode liest den kompletten Inhalt einer Textdatei von Anfang bis Ende und gibt ihn als einen großen String zurück.
string myFilePath = "notes.txt";
// Wichtig: Immer Existenz der Datei prüfen, um Fehler zu vermeiden!
if (File.Exists(myFilePath))
{
string content = File.ReadAllText(myFilePath);
Console.WriteLine($"Inhalt der Datei '{myFilePath}':\n{content}");
}
else
{
Console.WriteLine($"Fehler: Datei '{myFilePath}' wurde zum Lesen nicht gefunden.");
}
Wichtiger Hinweis: Die Methoden File.WriteAllText() und File.ReadAllText() sind super für kleine und mittlere Dateien (z.B. Notizen, Config-Dateien, kurze Logs). Aber wenn die Datei sehr groß ist (Dutzende oder Hunderte MB, oder gar GB), kann das Laden des gesamten Inhalts in einen String extrem viel RAM verbrauchen und sogar zu OutOfMemoryException führen. Für solche Fälle gibt es effizientere Ansätze (siehe unten und in den nächsten Vorlesungen).
3. Datei zeilenweise lesen
Wenn du mit großen Textdateien arbeitest, wie riesigen CSV-Reports, langen Logfiles oder Textdatenbanken, ist es ineffizient oder sogar unmöglich, sie komplett in den RAM zu laden. Hier hilft File.ReadLines().
File.ReadLines(path) – diese Methode lädt nicht die ganze Datei auf einmal. Stattdessen gibt sie eine spezielle Collection (IEnumerable<string>) zurück, mit der du die Datei Zeile für Zeile nach Bedarf lesen kannst. Das nennt man "Lazy Reading" oder "Streaming".
string logFilePath = "application.log";
string text = """
INFO: Anwendung gestartet.
WARN: Problem im Modul X entdeckt.
ERROR: Kritischer Netzwerkfehler.
INFO: Anwendung gestoppt.
""";
// Angenommen, wir haben eine Logdatei mit vielen Zeilen.
File.WriteAllText(logFilePath, text);
// Jede Schleifeniteration liest und verarbeitet nur EINE Zeile
foreach (string line in File.ReadLines(logFilePath))
Console.WriteLine($"- {line}");
Vorteil: Die Datei wird stückweise gelesen und verarbeitet, was den RAM-Verbrauch bei großen Dateien stark reduziert.
Unterschied zwischen File.ReadLines() und File.ReadAllLines():
- File.ReadAllLines(path): Lädt alle Zeilen der Datei auf einmal in den RAM und gibt sie als string[] zurück. Praktisch, wenn du alle Zeilen gleichzeitig brauchst (z.B. zum Sortieren oder Suchen).
- File.ReadLines(path): Gibt ein IEnumerable<string> zurück, mit dem du die Zeilen einzeln durchgehen kannst. Die Datei wird nur gelesen, wenn du die nächste Zeile anforderst (z.B. in einer foreach-Schleife). Das ist viel effizienter für sehr große Dateien, wenn du nicht alles auf einmal laden willst oder kannst.
4. Ein Array von Zeilen schreiben
Manchmal hast du eine Liste von Strings (z.B. aus einer Collection) und willst jede Zeile als eigenen Eintrag in die Datei schreiben.
File.WriteAllLines(path, contents)
Diese Methode nimmt ein String-Array (oder jede Collection von Strings) und schreibt jede Zeile einzeln in die Datei. Wie WriteAllText() überschreibt sie die Datei, falls sie schon existiert.
string membersFilePath = "participants.txt";
string[] names = { "Ivan Petrov", "Maria Sidorova", "Sergej Kozlov", "Anna Kuznezova" };
// Jede Zeile des Arrays wird als eigene Zeile in die Datei geschrieben
File.WriteAllLines(membersFilePath, names);
// Inhalt prüfen
Console.WriteLine($"Inhalt von '{membersFilePath}':");
foreach (string line in File.ReadLines(membersFilePath))
Console.WriteLine($"- {line}");
5. Mit Binärdateien arbeiten
Die Klasse File ist nicht nur auf Textdaten beschränkt. Sie bietet auch praktische Methoden zum Lesen und Schreiben von Binärdaten, also rohen Bytes. Das ist z.B. nützlich beim Speichern von Einstellungen in speziellem Format, bei Bildern, Audio oder beliebigen nicht-textuellen Daten.
Ein Byte-Array schreiben: File.WriteAllBytes() Erstellt oder überschreibt eine Datei und schreibt das komplette Byte-Array hinein.
string binaryDataPath = "settings.bin";
// Beispiel für Binärdaten: Bild, Video, beliebige Daten
byte[] settingsData = { 0x01, 0x0A, 0x2C, 0xFF, 0x00, 0x3F }; // Irgendwelche "rohen" Einstellungen
File.WriteAllBytes(binaryDataPath, settingsData);
Console.WriteLine($"Binärdaten wurden in die Datei '{binaryDataPath}' geschrieben.");
Wichtig: Wenn du 'settings.bin' im Editor öffnest, siehst du unlesbare Zeichen ("Krakel"), weil diese Bytes nicht als Text gedacht sind.
Ein Byte-Array lesen: File.ReadAllBytes() Liest den kompletten Inhalt einer Binärdatei in ein Byte-Array.
if (File.Exists(binaryDataPath))
{
byte[] readSettings = File.ReadAllBytes(binaryDataPath);
Console.WriteLine($"Gelesen wurden {readSettings.Length} Bytes aus der Datei '{binaryDataPath}'.");
Console.Write("Gelesene Bytes (hexadezimal): ");
foreach (byte b in readSettings)
Console.Write($"{b:X2} "); // :X2 formatiert das Byte als zweistellige Hex-Zahl
Console.WriteLine();
}
else
{
Console.WriteLine($"Fehler: Binärdatei '{binaryDataPath}' nicht gefunden.");
}
Diese Methoden sind sehr praktisch, um kleine Mengen Binärdaten zu speichern, z.B. für das Caching kleiner Bilder oder serialisierter Objekte.
6. Dateien auf der Festplatte verwalten
Die Klasse File bietet auch Methoden zur Verwaltung von Dateien auf der Festplatte.
Dateiexistenz prüfen: File.Exists(path) Gibt true zurück, wenn die Datei am angegebenen Pfad existiert, sonst false. Es ist sehr zu empfehlen, diese Methode vor Lese-, Lösch- oder anderen Operationen zu nutzen, die einen Fehler verursachen könnten, falls die Datei nicht existiert.
string myFileToCheck = "report.txt";
// Erstellt sie für das Beispiel
File.WriteAllText(myFileToCheck, "Testbericht.");
if (File.Exists(myFileToCheck))
{
Console.WriteLine($"Datei '{myFileToCheck}' gefunden.");
// Jetzt kann man sicher lesen, löschen usw.
}
else
{
Console.WriteLine($"Datei '{myFileToCheck}' nicht gefunden.");
}
Datei löschen: File.Delete(path) löscht die Datei unwiderruflich von der Festplatte. Sei vorsichtig, das ist nicht rückgängig zu machen!
string fileToDelete = "temp_file.txt";
// Datei für das Beispiel erstellen
File.WriteAllText(fileToDelete, "Diese Datei wird gelöscht.");
if (File.Exists(fileToDelete))
{
File.Delete(fileToDelete);
Console.WriteLine($"Datei '{fileToDelete}' wurde erfolgreich gelöscht.");
}
else
{
Console.WriteLine($"Datei '{fileToDelete}' existiert nicht mehr oder wurde schon gelöscht.");
}
7. Exceptions beim Arbeiten mit Dateien
Dateiarbeit ist immer mit Interaktion mit dem Betriebssystem und externen Ressourcen verbunden, was sie potenziell fehleranfällig macht.
Behandle Exceptions (Fehler)! Beim Arbeiten mit Dateien kann vieles schiefgehen, was dein Programm ordentlich abfangen sollte – nicht einfach "abstürzen". Typische Situationen:
- FileNotFoundException: Die Datei, auf die du zugreifen willst, existiert am angegebenen Pfad nicht.
- DirectoryNotFoundException: Der Ordner, in dem du die Datei erstellen oder finden willst, existiert nicht.
- UnauthorizedAccessException: Dein Programm hat keine Rechte zum Lesen, Schreiben oder Löschen der Datei/des Ordners (z.B. Systemdatei oder geschützter Bereich).
- IOException: Allgemeiner Ein-/Ausgabefehler, oft wenn die Datei von einem anderen Programm geöffnet und gesperrt ist oder kein Speicherplatz mehr da ist.
Benutze immer try-catch für sicheres Arbeiten mit Dateien. So kannst du Fehler "abfangen" und entsprechend reagieren (z.B. eine Nachricht anzeigen oder ins Log schreiben).
string sensitiveFilePath = "secret_data.txt";
try
{
// Versuch, eine Datei zu lesen, die evtl. nicht existiert oder auf die kein Zugriff besteht
string secretContent = File.ReadAllText(sensitiveFilePath);
Console.WriteLine($"Geheimer Inhalt gelesen: {secretContent}");
}
catch (FileNotFoundException) // Spezieller Fehler: Datei nicht gefunden
{
Console.WriteLine($"Fehler: Datei '{sensitiveFilePath}' nicht gefunden. Prüfe den Pfad.");
}
catch (IOException ex) // Allgemeiner IO-Fehler (z.B. Datei gesperrt)
{
Console.WriteLine($"IO-Fehler bei Datei '{sensitiveFilePath}': {ex.Message}");
}
catch (Exception ex) // Jeder andere unerwartete Fehler
{
Console.WriteLine($"Unerwarteter Fehler: {ex.Message}");
}
8. Wann ist System.IO.File nicht die beste Wahl?
Obwohl die Klasse File erstaunlich vielseitig ist, gibt es Szenarien, in denen sie nicht optimal oder sogar ungeeignet ist:
Riesige Dateien (Dutzende+ GB): Die Methoden ReadAllText()/ReadAllBytes() laden die ganze Datei in den RAM. Bei extrem großen Dateien führt das zu OutOfMemoryException. In solchen Fällen brauchst du File.ReadLines() (für Text) oder einen direkten Ansatz mit Streams (FileStream) für das Lesen/Schreiben in Teilen. (Mehr zu Streams in der nächsten Vorlesung).
Feinsteuerung des Dateizugriffs: Wenn du sehr spezifisch steuern willst, wie eine Datei geöffnet wird (z.B. exklusiver Zugriff, damit niemand sonst lesen oder schreiben kann, oder umgekehrt, gleichzeitiger Lesezugriff durch mehrere Prozesse), bietet File diese Details nicht. Dafür brauchst du Low-Level-Stream-Klassen.
Asynchrone Operationen: Für High-Performance-Anwendungen, die Dateioperationen ausführen müssen, ohne den Hauptthread zu blockieren (z.B. Webserver), brauchst du asynchrone Methoden (wie ReadAllTextAsync()), die ebenfalls auf Streams basieren.
Teilweises Lesen/Schreiben: Wenn du nur einen Teil der Datei ab einem bestimmten Offset lesen oder Daten mitten in eine bestehende Datei schreiben willst, reichen die Methoden von File nicht aus. Dafür brauchst du direkten Zugriff auf den Dateistream.
9. Zusammenfassung
Warum ist System.IO.File so beliebt?
- Einfachheit und Kürze: Die statischen Methoden ermöglichen komplexe Operationen in ein bis zwei Zeilen Code. Das macht die Entwicklung viel einfacher und den Code lesbarer.
- Automatisches Ressourcenmanagement: File kümmert sich selbst um das Öffnen und Schließen von Dateien bei jeder Operation, sodass du dich nicht manuell um Ressourcen kümmern musst (was oft zu Fehlern führt).
- Vielseitigkeit für Alltagsaufgaben: Für die meisten typischen Aufgaben mit kleinen und mittleren Text- und Binärdateien reichen die Möglichkeiten von File völlig aus.
- Weit verbreitet: In den meisten Praxisaufgaben und bei Vorstellungsgesprächen wird erwartet, dass du die Methoden der Klasse File sicher anwenden kannst.
- Versteckte Komplexität: Alle Methoden sind so geschrieben, dass sie die komplexe Logik der Betriebssystem-Interaktion kapseln und dir ein sauberes, verständliches Interface bieten.
Häufige Fragen und Klarstellungen
Wie groß darf eine Datei für File.ReadAllText() maximal sein?
Für Dateien bis zu einigen Dutzend Megabyte (< 100 MB) gibt es normalerweise keine Probleme. Ist die Datei größer (Hunderte MB, GB), kann die Nutzung von File.ReadAllText() zu RAM-Überlauf (OutOfMemoryException) führen. In solchen Fällen solltest du File.ReadLines() für zeilenweises Lesen oder fortgeschrittene Streaming-Tools verwenden, über die du später mehr lernst.
Kann man eine Datei in einem Ordner erstellen/schreiben, der nicht existiert?
Nein. Die Methoden File.WriteAllText(), File.WriteAllBytes() und andere erstellen keine übergeordneten Verzeichnisse automatisch. Wenn du z.B. den Pfad C:\MyAppData\Logs\current.log angibst, aber MyAppData oder Logs nicht existieren, bekommst du eine DirectoryNotFoundException. Du musst also vorher sicherstellen, dass alle nötigen Ordner existieren, z.B. mit System.IO.Directory (Directory.CreateDirectory("myfolder")).
Wie erfahre ich das Erstellungsdatum, Änderungsdatum oder die Größe einer Datei?
Für detaillierte Infos wie Erstellungsdatum, letztes Änderungsdatum, Größe, Attribute (versteckt, schreibgeschützt usw.) nutze die Klasse System.IO.FileInfo. Sie bietet viele nützliche Properties.
GO TO FULL VERSION