C# Datei lesen schreiben: StreamReader & StreamWriter einfach erklärt
Mit File, StreamReader und StreamWriter liest und schreibst du in C# Dateien – Schritt für Schritt erklärt mit Codebeispielen für deinen Einstieg.
By Marcel Schmidtpeter 16 Sept 2026
In C# Dateien lesen und schreiben zu können gehört zu den Grundlagen, die in fast jeder Prüfung und in jedem echten Projekt auftauchen. Ob du als Azubi eine Logdatei auswerten sollst, im Studium Daten aus einer Textdatei einlesen musst oder in deinem ersten Job Konfigurationsdateien verarbeitest - irgendwann führt kein Weg an `StreamReader` und `StreamWriter` vorbei.
In diesem Beitrag baust du Schritt für Schritt ein kleines Notizprogramm: Es schreibt Einträge in eine Textdatei, hängt neue Notizen an und liest alles wieder aus. Am Ende verstehst du, wann du welche Klasse nutzt und wie du typische Fehler vermeidest.
Voraussetzungen: Was brauchst du?
Du brauchst nur eine C#-Entwicklungsumgebung und etwas Grundlagenwissen:
Visual Studio 2022 (kostenlose Community Edition) oder Visual Studio Code mit C#-Extension
.NET 6 oder neuer - die Beispiele nutzen die aktuelle Syntax
Grundlagen: Variablen, Schleifen und Methoden
Hilfreich, aber nicht Pflicht: Grundverständnis für Exception Handling in C#, denn Dateizugriffe können Fehler werfen
Dateien in C# lesen und schreiben: Was sind StreamReader und StreamWriter?
`StreamWriter` schreibt Zeichen in eine Datei, `StreamReader` liest Zeichen aus einer Datei. Beide Klassen leben im Namespace `System.IO` - der Ordnungsstruktur für alles, was mit Dateien zu tun hat - und arbeiten zeilenweise. Das macht sie ideal für Textdateien wie Logs, CSV-Dateien oder Konfigurationen.
Stell dir die beiden wie einen Wasserhahn vor: Du öffnest ihn (`new StreamWriter(...)`), lässt Wasser fließen (`WriteLine`) und schließt ihn wieder (`Close` bzw. `Dispose`). Vergisst du das Schließen, bleibt die Datei gesperrt - genau wie ein offener Hahn das Wasser blockiert.
Merke: `StreamWriter` = schreiben, `StreamReader` = lesen. Beide gehören zu `System.IO` und müssen nach der Nutzung freigegeben werden.
Schritt 1: Wie schreibst du eine Datei mit StreamWriter?
Mit `StreamWriter` schreibst du Text zeilenweise in eine Datei. Ist die Datei nicht vorhanden, wird sie automatisch erstellt. Der wichtigste Baustein ist die `using`-Anweisung - sie sorgt dafür, dass die Datei garantiert geschlossen wird, selbst wenn ein Fehler auftritt.
using System;
using System.IO;
class Program
{
static void Main()
{
using (StreamWriter writer = new StreamWriter("notizen.txt"))
{
writer.WriteLine("Erste Notiz: StreamReader lernen");
writer.WriteLine("Zweite Notiz: StreamWriter ausprobieren");
}
Console.WriteLine("Datei geschrieben.");
}
}Was passiert hier?
`using (...)` gibt die Ressource automatisch frei, sobald der Block endet - egal ob erfolgreich oder mit Fehler
`WriteLine` schreibt eine Zeile inklusive Zeilenumbruch
Ohne `using` müsstest du `writer.Close()` manuell aufrufen - und das in keinem Fall vergessen
Schritt 2: Wie liest du eine Datei mit StreamReader?
Mit `StreamReader` liest du eine Textdatei Zeile für Zeile aus. Die gängigste Variante ist eine `while`-Schleife, die so lange läuft, bis das Dateiende erreicht ist - `ReadLine()` liefert dann `null` zurück.
using System;
using System.IO;
class Program
{
static void Main()
{
using (StreamReader reader = new StreamReader("notizen.txt"))
{
string zeile;
while ((zeile = reader.ReadLine()) != null)
{
Console.WriteLine(zeile);
}
}
}
}Der Ausdruck `(zeile = reader.ReadLine()) != null` sieht erstmal kryptisch aus. Er macht zwei Dinge auf einmal: Er liest die nächste Zeile in die Variable `zeile` und prüft gleichzeitig, ob dort noch etwas drinstand. Das ist ein klassisches C#-Muster, das dir in vielen Codebeispielen begegnen wird.
Merke: `ReadLine()` gibt `null` zurück, wenn keine Zeilen mehr übrig sind - genau daran erkennst du das Dateiende.
Schritt 3: Wie hängst du Inhalte an, statt zu überschreiben?
Der zweite Konstruktor-Parameter `append` entscheidet, ob vorhandene Inhalte gelöscht werden. Standardmäßig überschreibt `StreamWriter` die komplette Datei. Für Logdateien oder Notizen willst du aber meist anhängen.
// Ueberschreibt alles:
using (StreamWriter writer = new StreamWriter("notizen.txt"))
{
writer.WriteLine("Alte Inhalte sind weg.");
}
// Haengt ans Ende an:
using (StreamWriter writer = new StreamWriter("notizen.txt", append: true))
{
writer.WriteLine("Neue Notiz kommt dazu.");
}Merke: Ohne `append: true` löscht `StreamWriter` den bisherigen Inhalt der Datei. Für Logdateien fast immer `append: true` nutzen.
StreamReader oder File-Klasse? Der Vergleich
Für kleine Dateien gibt es Abkürzungen über die statische Klasse `File` - für große Dateien solltest du bei Streams bleiben. Statisch heißt: Du rufst die Methoden direkt über den Klassennamen auf, ohne ein Objekt zu erstellen. Die folgende Tabelle hilft dir bei der Wahl:
Methode | Gut für | Lädt alles in den Speicher? |
`StreamReader.ReadLine()` | Große Dateien, zeilenweise Verarbeitung | Nein |
`File.ReadAllLines()` | Kleine Dateien, braucht Array-Zugriff | Ja |
`File.ReadAllText()` | Kleine Dateien, ein String als Ergebnis | Ja |
`StreamWriter` | Zeilenweise oder streaming schreiben | Nein |
`File.WriteAllText()` | Kompletten Text in einem Rutsch schreiben | Ja |
Bei einer 2-GB-Logdatei würde `File.ReadAllLines` deinen Speicher sprengen. `StreamReader` arbeitet dagegen wie ein Buch: Du liest Seite für Seite, nie das ganze Buch gleichzeitig. Die offizielle Dokumentation dazu findest du bei Microsoft Learn.
Faustregel: Große Dateien → Streams (`StreamReader`/`StreamWriter`). Kleine Dateien → `File`-Klasse.
Vollständiges Beispiel: Ein Notizprogramm
Alle Bausteine zusammen ergeben ein lauffähiges Konsolenprogramm:
using System;
using System.IO;
class Program
{
static void Main()
{
string dateiPfad = "notizen.txt";
// 1. Notizen schreiben
using (StreamWriter writer = new StreamWriter(dateiPfad))
{
writer.WriteLine("Einkaufsliste");
writer.WriteLine("- Kaffee");
writer.WriteLine("- Tastatur");
}
// 2. Neue Notiz anhaengen
using (StreamWriter writer = new StreamWriter(dateiPfad, append: true))
{
writer.WriteLine("- Monitor");
}
// 3. Alles wieder lesen
Console.WriteLine("--- Notizen ---");
using (StreamReader reader = new StreamReader(dateiPfad))
{
string zeile;
while ((zeile = reader.ReadLine()) != null)
{
Console.WriteLine(zeile);
}
}
}
}Die Ausgabe im Terminal:
--- Notizen ---
Einkaufsliste
- Kaffee
- Tastatur
- MonitorHäufige Probleme & Lösungen
Problem 1: Die Datei ist gesperrt (IOException)
Öffnest du die Textdatei parallel in Excel oder einem anderen Programm, wirft C# eine `IOException`: *"The process cannot access the file because it is being used by another process."* Schließe das andere Programm und starte deinen Code erneut. Auch ein vergessenes `Dispose` im eigenen Code kann die Sperre verursachen.
Problem 2: Umlaute werden falsch angezeigt
Sind Sonderzeichen kaputt, stimmt die Zeichenkodierung nicht - also die Vorschrift, wie Zeichen als Bytes gespeichert werden. Lösung: UTF-8 explizit angeben:
using (StreamReader reader = new StreamReader("notizen.txt",
System.Text.Encoding.UTF8))
{
// ...
}Details dazu liefert die Encoding-Dokumentation bei Microsoft Learn.
Problem 3: FileNotFoundException
Liest du eine nicht existierende Datei, crasht das Programm mit einer `FileNotFoundException`. Prüfe vorher mit `File.Exists("notizen.txt")`, ob die Datei vorhanden ist - oder fange den Fehler sauber mit `try-catch` ab, wie wir es im Artikel zum Exception Handling in C# beschreiben.
FAQ: Häufige Fragen zum Dateizugriff in C#
Was macht die using-Anweisung bei StreamReader und StreamWriter?
`using` ruft automatisch die `Dispose()`-Methode auf und schließt die Datei, sobald der Block endet - auch bei Fehlern. Ohne `using` bleibt die Datei gesperrt, bis der Garbage Collector (die automatische Speicherbereinigung von C#) aufräumt. Das kann dauern oder dein Programm blockieren.
Wann nutze ich StreamReader statt File.ReadAllLines?
`StreamReader` bei großen Dateien (ab ein paar Megabytes), weil er speicherschonend Zeile für Zeile arbeitet. `File.ReadAllLines` bei kleinen Dateien, wenn du ohnehin alle Zeilen als Array brauchst - etwa zum Filtern mit LINQ.
Wie hänge ich an eine Datei an, ohne sie zu überschreiben?
Beim Konstruktor den zweiten Parameter auf `true` setzen: `new StreamWriter("datei.txt", true)`. Alternativ gibt es die Methode `File.AppendAllText()`.
Was ist der Unterschied zwischen Write und WriteLine?
`Write` schreibt Text ohne Umbruch, `WriteLine` hängt einen Zeilenumbruch an. Das Gegenstück `ReadLine` liest dann genau bis zu diesem Umbruch.
Kann ich Dateien auch asynchron lesen und schreiben?
Ja - mit `ReadLineAsync()` und `WriteLineAsync()` bleiben UI oder Server responsiv. Wie das genau funktioniert, erklären wir im Beitrag zu async und await in C#.
Fazit: Dateien lesen und schreiben in C# ist kein Hexenwerk
Mit `StreamWriter` schreibst du Text, mit `StreamReader` liest du ihn zeilenweise wieder aus - und die `using`-Anweisung sorgt dafür, dass die Datei immer sauber geschlossen wird. Wichtigster Merksatz: Bei großen Dateien Streams nutzen, bei kleinen reicht die `File`-Klasse.
Wenn du bei C#-Themen wie Dateizugriff, Exceptions oder generell bei der Prüfungsvorbereitung festhängst: Schau dir study-it.education an. Dort bekommst du individuelle Nachhilfe für Azubis, Studenten und Berufseinsteiger - genau auf deinem Niveau, mit echten Praxisbeispielen statt trockener Theorie.
Need someone to walk through this with you?
Instead of re-reading: 30 min with a senior dev.
Book a free first chat →
Mit File, StreamReader und StreamWriter liest und schreibst du in C# Dateien – Schritt für Schritt erklärt mit Codebeispielen für deinen Einstieg.
marcel.schmidtpeter@study-it.education →More reading
C# JSON mit System.Text.Json lesen & schreiben – einfach erklärt
JSON-Daten in C# lesen und schreiben? Mit System.Text.Json gelingt dir Serialisierung & Deserialisierung – einfach erklärt für alle IT-Einsteiger.
C# xUnit Unit Test: So schreibst du deine ersten Unit Tests
Unit Tests mit xUnit machen deinen C#-Code belastbar. In diesem Tutorial lernst du [Fact], [Theory] und Assert kennen – für Einsteiger erklärt.
C# Datenbank verbinden: ADO.NET & Entity Framework einfach erklärt
So greifst du aus C# auf Datenbanken zu: mit ADO.NET für direktes SQL oder EF Core als modernem ORM – beide Wege mit Beispielen erklärt.