1. Einführung
Direkt mit Streams zu arbeiten (StreamReader, StreamWriter, FileStream) ist sehr nützlich, besonders wenn du den Lese-/Schreibvorgang auf niedrigem Level kontrollieren musst: z.B. in Blöcken "nach und nach" schreiben oder große Dateien stückweise verarbeiten.
In der Praxis will man aber oft einfach nur wissen: "Existiert diese Datei?", "Datei von A nach B kopieren", "Datei löschen", "Liste aller .txt-Dateien im Ordner bekommen" usw. Für solche Aufgaben hat Microsoft zwei universelle Werkzeuge geschaffen: die statischen Klassen File und Directory. Statisch bedeutet: keine Instanz erzeugen, du rufst die Methode direkt am Klassennamen auf.
Lebensnahe Analogie
Wenn Streams du mit einem Bleistift sind, der sorgfältig jeden Buchstaben auf ein Blatt schreibt, dann sind File und Directory dein Schreibtisch mit Schubladen: du kannst schnell eine Schublade öffnen (Directory), einen Zettel herausnehmen (File.ReadAllText), den Zettel wegwerfen (File.Delete) oder sogar eine ganze Schublade aus dem Schrank ziehen und ans andere Ende des Zimmers bringen (Directory.Move). Einfache Aufgaben — einfache Methoden.
2. Die Klasse File: was sie ist und wofür sie gut ist
Die Klasse File bietet eine praktische Sammlung statischer Methoden für alle gängigen Dateioperationen.
Am häufigsten verwendete Methoden
| Methode | Beschreibung |
|---|---|
|
Prüft, ob eine Datei unter dem Pfad existiert |
|
Liess die ganze Datei als Text |
|
Liess alle Zeilen der Datei in ein Array |
|
Überschreibt die Datei und schreibt Text hinein |
|
Hängt Text am Ende der Datei an |
|
Kopiert eine Datei |
|
Löscht eine Datei |
|
Verschiebt oder benennt eine Datei um |
|
Öffnet einen Stream für komplexe Operationen |
Schnelles Beispiel: Datei prüfen und lesen
string filePath = "data.txt";
if (File.Exists(filePath))
{
string content = File.ReadAllText(filePath);
Console.WriteLine("Inhalt der Datei:");
Console.WriteLine(content);
}
else
{
Console.WriteLine("Datei nicht gefunden!");
}
Siehst du? Kein manuelles Stream-Management für den einfachen Fall!
3. Die Klasse Directory: Verzeichnisse schmerzfrei verwalten
Wenn File für einzelne Dateien ist, dann ist Directory für Ordner (Directories).
Wesentliche Aufgaben
| Methode | Beschreibung |
|---|---|
|
Prüft, ob ein Ordner existiert |
|
Erstellt einen Ordner (inkl. aller Zwischenordner) |
|
Löscht einen Ordner (optional mit Unterverzeichnissen) |
|
Gibt die Liste der Dateien in einem Ordner zurück |
|
Gibt die Liste der Unterverzeichnisse zurück |
|
Verschiebt oder benennt einen Ordner um |
|
Holt das aktuelle Arbeitsverzeichnis der Anwendung |
Beispiel: Ordner erstellen und Datei dort speichern
string dirPath = "Results";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
Console.WriteLine("Ordner 'Results' wurde erstellt.");
}
string filePath = Path.Combine(dirPath, "summary.txt");
File.WriteAllText(filePath, "Ergebnisdaten: ...");
Console.WriteLine($"Datei {filePath} wurde geschrieben.");
4. Typische Anwendungsszenarien für File und Directory
Die Basis-Methoden wirken langweilig, wenn man sie nicht in Aktion sieht! Schauen wir, wie man diese Klassen in echten Aufgaben nutzt und erweitern unser fiktives kleines Programm (nehmen wir an, wir bauen ein einfaches todo-list System, das Ergebnis speichern wir in Dateien).
Daten in Datei speichern (alte Datei ersetzen)
// Speichere die Aufgabenliste in eine Datei
string[] todos = { "Kupiit khleb", "Pozvonit vrachu", "Sdelat domashku po C#" };
string filePath = "todo.txt";
File.WriteAllLines(filePath, todos);
Console.WriteLine("Aufgabenliste gespeichert.");
Daten aus Datei laden
// Lade Aufgaben, falls die Datei existiert
if (File.Exists(filePath))
{
string[] loadedTodos = File.ReadAllLines(filePath);
Console.WriteLine("Deine Aufgabenliste:");
foreach (var task in loadedTodos)
{
Console.WriteLine("- " + task);
}
}
else
{
Console.WriteLine("Du hast noch keine Aufgabenliste.");
}
Neue Aufgabe hinzufügen (ohne Datei zu überschreiben)
string newTask = "Pogulyat s sobakoy";
File.AppendAllText(filePath, newTask + Environment.NewLine);
Console.WriteLine("Aufgabe hinzugefügt!");
Datei kopieren und Backup erstellen
string backupPath = "todo_backup.txt";
File.Copy(filePath, backupPath, overwrite: true);
Console.WriteLine("Backup der Aufgabenliste erstellt.");
Datei verschieben (oder umbenennen)
string archivePath = "todo_archive.txt";
File.Move(filePath, archivePath);
Console.WriteLine("Aufgabenliste archiviert (umbenannt).");
Datei löschen
if (File.Exists(archivePath))
{
File.Delete(archivePath);
Console.WriteLine("Archiv gelöscht — Speicher freigemacht!");
}
5. Arbeiten mit Ordnern: Beispiele
Erstellen einer Verzeichnis-Hierarchie
string path = Path.Combine("Reports", "2024", "June");
Directory.CreateDirectory(path);
Console.WriteLine($"Ordner {path} erstellt (inklusive Zwischenordner).");
Datei- und Ordnerliste erhalten
string dirPath = "Reports";
if (Directory.Exists(dirPath))
{
string[] files = Directory.GetFiles(dirPath);
Console.WriteLine("Dateien im Ordner:");
foreach (var file in files)
{
Console.WriteLine(file);
}
string[] subDirs = Directory.GetDirectories(dirPath);
Console.WriteLine("Unterverzeichnisse:");
foreach (var dir in subDirs)
{
Console.WriteLine(dir);
}
}
Dateien nach Maske filtern (nur txt)
string[] txtFiles = Directory.GetFiles(dirPath, "*.txt");
Console.WriteLine("Nur .txt-Dateien:");
foreach (var file in txtFiles)
{
Console.WriteLine(file);
}
Rekursives Durchlaufen (Dateien in allen Unterordnern)
string[] allFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories);
Console.WriteLine("Dateien in allen verschachtelten Ordnern:");
foreach (var file in allFiles)
{
Console.WriteLine(file);
}
Verschieben und Löschen von Verzeichnissen
string from = "OldReports";
string to = "Archive/OldReports";
if (Directory.Exists(from))
{
Directory.Move(from, to);
Console.WriteLine($"Ordner {from} wurde nach {to} verschoben");
}
if (Directory.Exists(to))
{
Directory.Delete(to, recursive: true); // true: alles darin löschen
Console.WriteLine($"Ordner {to} gelöscht (inkl. Inhalt).");
}
6. Nützliche Feinheiten
Integration mit Pfaden: die Klasse Path
Beim Arbeiten mit Dateien und Ordnern muss man oft volle Pfade zusammensetzen, Verzeichnis- und Dateinamen verbinden, Erweiterungen auslesen oder ungültige Zeichen prüfen. Dafür gibt es die Hilfsklasse Path.
Beispiele
string folder = "Results";
string filename = "week1.txt";
string fullPath = Path.Combine(folder, filename); // sicheres Zusammenfügen!
Console.WriteLine(fullPath); // "Results/week1.txt" (oder "\" auf Windows)
- Dateierweiterung bekommen: Path.GetExtension(fullPath)
- Dateiname ohne Pfad: Path.GetFileName(fullPath)
Verwende Path.Combine statt String-Konkatenation — das ist sicherer für plattformübergreifende Anwendungen.
„Alles auf einmal“-Methoden vs. stream-basierte Varianten
Viele Methoden von File und Directory (z.B. File.ReadAllText, File.WriteAllText, Directory.GetFiles) erledigen die Arbeit "komplett": sie lesen/schreiben/lesen die Dateiliste in einem Rutsch. Das ist SEHR praktisch, aber nicht geeignet für extrem große Dateien oder Verzeichnisse, wo der Speicher erschöpft sein könnte. Bei Gigabyte-Dateien wechselst du zu Streams (StreamReader, StreamWriter, FileStream usw.) oder verarbeitest die Daten stückweise.
Wann File/Directory verwenden und wann Streams
| Situation | Was verwenden |
|---|---|
| Du willst prüfen, ob Datei/Ordner existiert | |
| Eine kleine Datei komplett lesen/schreiben | |
| Text an eine Datei anhängen | |
| Dateiliste in einem Verzeichnis bekommen | |
| Datei kopieren, löschen, verschieben | |
| Ganzen Ordner kopieren/löschen | Directory.Delete/Move/Copy (Copy — mit externer Bibliothek) |
| Sehr große Dateien stückweise verarbeiten | Stream-Klassen (StreamReader, FileStream) |
Praxisrelevanz und echte Anwendungen
- Schnelles Laden/Speichern von Konfigurationen, Settings, JSON-/XML-Dateien.
- Logging-Systeme (Logs auf Festplatte schreiben).
- Einfache Backup-Utilities und Datenmigrationen.
- Scannen von Ordnern mit Medien, Fotos, Dokumenten.
- Benutzer-Szenarios: Templates laden, Import/Export, Reports generieren usw.
Bei Coding-Interviews kommen oft Aufgaben, die genau diese Klassen verlangen: "Implementiere eine Funktion, die die Gesamtgröße aller .txt-Dateien in einem Verzeichnis berechnet", "Erstelle ein Backup der Dateien in ein separates Verzeichnis" usw.
Visuelle Spickzettel: welches Methode wann
graph TD
A[Was willst du tun?]
A -->|Existenz prüfen| B[File.Exists oder Directory.Exists]
A -->|Datei komplett lesen/schreiben| C[File.ReadAllText/WriteAllText]
A -->|Daten an Datei anhängen| D[File.AppendAllText]
A -->|Mit Ordnern arbeiten| E[Directory.CreateDirectory, GetFiles, GetDirectories]
A -->|Datei kopieren/löschen/verschieben| F[File.Copy/Delete/Move]
A -->|Ordner komplett kopieren/löschen| G[Directory.Delete/Move]
7. Besonderheiten und typische Fehler
Existenzprüfung und "Race-Condition". Selbst wenn du prüfst, ob eine Datei/ein Ordner existiert, kann zwischen dieser Prüfung und der eigentlichen Operation ein anderer Prozess die Situation ändern. Deshalb immer try-catch verwenden, auch wenn du vorher geprüft hast!
Zugriffsrechte. Wenn der Anwendung die Rechte zum Lesen/Schreiben/Löschen fehlen, werfen die Methoden eine UnauthorizedAccessException.
Pfad zu lang. Maximale Pfadlänge (meist 260 Zeichen auf älteren Windows; in .NET 9 sind die Einschränkungen gelockert, aber Vorsicht ist geboten).
Fehlerbehandlung. Methoden wie File.ReadAllText oder Directory.GetFiles verzeihen keine Fehler: wenn Datei/Ordner fehlt — wird sofort eine Ausnahme geworfen. Pack die Aufrufe in try-catch oder prüfe vorher das Vorhandensein.
GO TO FULL VERSION