1. Einführung
Fangen wir mit der zentralen Frage an — warum sich überhaupt mit Encodings beschäftigen? Man könnte denken: eine Datei, ein Encoding, alles sollte ruhig sein. In der Realität ist es aber deutlich spannender. Sehr schnell stellt sich heraus, dass eine Datei von überallher kommen kann und in völlig unerwartetem Encoding vorliegt. Und deine Anwendung erwartet natürlich etwas ganz anderes.
Manchmal musst du dich mit einer API oder einem System integrieren, das strikt vorgibt: nur dieses eine Encoding und sonst nichts. Es kann auch passieren, dass du eine alte Datei findest, der zehn Jahre alt ist, und versuchst, sie in einem neuen Editor zu öffnen — und da sind plötzlich mojibake. Oder du speicherst einen CSV-Bericht und willst sicherstellen, dass alle Kollegen ihn korrekt öffnen können — unter Windows, auf dem Mac und sogar in Excel.
Kurz gesagt: Umkodierung ist nichts Seltenes oder Exotisches. Im Gegenteil, das ist eine sehr reale und ziemlich häufige Aufgabe, die überall auftaucht: beim Export aus Datenbanken, beim Umgang mit Archiven, bei Integrationen mit der Buchhaltung oder in Automatisierungsskripten. Je früher man sich damit auseinandersetzt, desto weniger Überraschungen später.
Vom alten Encoding zum neuen
Um eine Datei umzukodieren, sind zwei Schritte nötig:
- Die Datei lesen im Quell-Encoding und die Strings (oder Zeichen) erhalten.
- Die Strings schreiben in eine neue Datei, wobei das gewünschte Ziel-Encoding explizit angegeben wird.
Analogie: Stell dir vor, du übersetzt ein Buch von Französisch ins Russische. Zuerst musst du Französisch lesen können (den Text erfassen), dann denselben Sinn auf Russisch ausdrücken (den Text schreiben).
In C# (und .NET) macht man das, indem man das passende Encoding-Objekt im Konstruktor von StreamReader (zum Lesen) und StreamWriter (zum Schreiben) angibt.
Überblick über Encodings und die Klasse Encoding
Alle "magischen" Zeichenumwandlungen werden mit der Klasse System.Text.Encoding durchgeführt.
Eine Tabelle mit den wichtigsten Encodings und wie man sie in C# bekommt, sieht so aus:
| Encoding | Beschreibung | C# Konstante |
|---|---|---|
| UTF-8 | Universell, standardmäßig ohne BOM | |
| UTF-8 mit BOM | Dasselbe, aber mit BOM-Signatur | |
| UTF-16 (LE/BE) | "Wide char", little-endian | Encoding.Unicode (LE), Encoding.BigEndianUnicode (BE) |
| ASCII | 7-bit Klassiker | |
| Windows-1251 | Beliebt für Kyrillisch | |
| ISO-8859-1 | Lateinische Zeichen (europäisch) | |
Hinweis: Für ältere Encodings muss man Encoding.GetEncoding verwenden, manchmal mit einer Nummer (1251), manchmal mit einem String ("windows-1251").
2. Umkodierung: schrittweise Strategie in C#
Schauen wir uns an, wie man Umkodierung praktisch umsetzt.
Algorithmus
- Die Quell-Datei mit StreamReader öffnen und das Quell-Encoding explizit angeben.
- Den Text lesen (ganz oder zeilenweise — abhängig von der Dateigröße).
- Die Zieldatei mit StreamWriter öffnen und das gewünschte Ziel-Encoding angeben.
- Den Text in die Zieldatei schreiben.
- Ströme schließen nicht vergessen — benutze using für Zuverlässigkeit!
Beispiel: Umkodierung Windows-1251 → UTF-8
Angenommen, wir haben eine Datei "input-1251.txt" im Encoding Windows-1251 und wollen "output-utf8.txt" im "sauberen" UTF-8 (ohne BOM).
// Wir geben die Quelle mit dem Quell-Encoding an
using var reader = new StreamReader("input-1251.txt", Encoding.GetEncoding(1251));
using var writer = new StreamWriter("output-utf8.txt", false, Encoding.UTF8);
string line;
// Zeilenweise lesen — praktisch für große Dateien
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
Console.WriteLine("Die Datei wurde erfolgreich von Windows-1251 nach UTF-8 umkodiert!");
Dieser Code stellt sicher, dass jede Zeile korrekt von einem Encoding ins andere konvertiert wird.
Schematisch sieht das so aus:
┌───────────────────────────────┐ ┌───────────────────┐ ┌───────────────────────────────┐
│ Datei "input-1251.txt" (1251) │ --> │ StreamReader │ --> │ Strings vom Typ string im RAM│
└───────────────────────────────┘ │ (Encoding 1251) │ └───────────────────────────────┘
└───────────────────┘
│
▼
┌────────────────────────┐
│ StreamWriter │
│ (Encoding UTF-8) │
└───────────┬────────────┘
│
▼
┌──────────────────────────────┐
│ "output-utf8.txt" (UTF-8) │
└──────────────────────────────┘
3. Praktisches Beispiel: Encoding-Konverter
Verschärfen wir die Aufgabe: schreiben wir ein einfaches Konverterprogramm, in dem der Benutzer Quell- und Zieldatei sowie die Encodings wählen kann.
Console.WriteLine("Geben Sie den Pfad zur Quelldatei ein:");
string inputPath = Console.ReadLine();
Console.WriteLine("Quell-Encoding der Datei (z.B. 1251, utf-8):");
string sourceEncodingName = Console.ReadLine();
Console.WriteLine("Geben Sie den Pfad zur Zieldatei ein:");
string outputPath = Console.ReadLine();
Console.WriteLine("Encoding zum Speichern (z.B. utf-8, 1251):");
string destEncodingName = Console.ReadLine();
Encoding sourceEncoding = Encoding.GetEncoding(sourceEncodingName);
Encoding destEncoding = Encoding.GetEncoding(destEncodingName);
using var reader = new StreamReader(inputPath, sourceEncoding);
using var writer = new StreamWriter(outputPath, false, destEncoding);
string line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
Console.WriteLine("Fertig! Prüfen Sie das Ergebnis.");
Tipp: Wenn du dir unsicher bist, welches Encoding anzugeben ist, schaue in die Dokumentation oder probiere verschiedene Varianten. Manchmal lässt sich eine Datei nur experimentell "identifizieren", wenn niemand ein hilfreiches README hinterlassen hat.
4. Wichtige Feinheiten: BOM, "unsichtbare" Zeichen und Spezialfälle
Wie fügt man BOM beim Speichern hinzu?
Standardmäßig erzeugt Encoding.UTF8 in C# Dateien ohne BOM (Byte Order Mark). Wenn du eine Datei mit BOM erzeugen willst, verwende:
// true — bedeutet "mit BOM"
var utf8WithBom = new UTF8Encoding(true);
using var writer = new StreamWriter("with-bom.txt", false, utf8WithBom);
writer.WriteLine("Text mit BOM");
Die Datei beginnt dann mit den "unsichtbaren" drei Bytes: 0xEF, 0xBB, 0xBF.
Wann ist BOM schädlich?
- Wenn du CSV für Excel exportierst, stört BOM bei vielen internationalen Versionen eher — es können seltsame Zeichen erscheinen.
- In Unix-ähnlichen Systemen (Linux) kann BOM die Dateiverarbeitung manchmal kaputtmachen.
- Bei JSON-Dateien ist BOM fast immer schädlich, viele Parser kommen damit nicht klar!
Tipp: Wähle bewusst, ob du BOM brauchst, und "füge" ihn nur bei Bedarf hinzu.
Schleichende Zeichen und magische Zahlen
Wenn beim Öffnen einer umkodierten Datei das Programm Formatfehler ausgibt, hast du vielleicht unsichtbare Zeichen am Dateianfang (z.B. BOM) nicht berücksichtigt oder das falsche Encoding gewählt (z.B. als ASCII gelesen, obwohl es kyrillische Zeichen in 1251 sind). Prüfe immer, welche Encodings deine Anwendung/Kollegen/Server verwenden.
5. Nützliche Hinweise
Arbeiten mit großen Dateien: warum zeilenweise statt komplett?
Man könnte einfach:
string allText = File.ReadAllText("input.txt", Encoding.GetEncoding(1251));
File.WriteAllText("output.txt", allText, Encoding.UTF8);
Dieser Ansatz funktioniert für kleine und mittelgroße Dateien (sagen wir bis ~50 MB). Wenn die Datei aber groß ist, wird der gesamte Text in den Arbeitsspeicher geladen — und bei mehreren GB gibt es Probleme. Deshalb verwenden wir für Robustheit zeilenweises Lesen/Schreiben.
Umkodierung zwischen weniger verbreiteten Encodings
Angenommen, du hast plötzlich eine Datei in ISO-8859-1 (MySQL-Exporte lieben das) und willst sie in Unicode bekommen.
var sourceEnc = Encoding.GetEncoding("iso-8859-1");
var destEnc = Encoding.UTF8;
using var reader = new StreamReader("data-latin.txt", sourceEnc);
using var writer = new StreamWriter("data-unicode.txt", false, destEnc);
string line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
Dieser Ansatz funktioniert mit jedem Encoding, das in .NET unterstützt wird.
Umkodierung von Binärdateien — nicht tun!
Das oben beschriebene Programm ist ausschließlich für Textdateien gedacht. Wenn die Datei binär ist (z.B. Bild, Audio, Archiv), wird der Versuch, sie als Text zu lesen und wieder zu schreiben, die Bytes zerstückeln, zu vielen "mojibake" führen und die Datei unbrauchbar machen. Für Binärdateien macht "Encoding" keinen Sinn.
Zuordnungs-Tabelle: welches Encoding wofür nützlich ist
| Encoding | Wann verwenden |
|---|---|
| UTF-8 | Universelle Dateien, Web, moderne Anwendungen |
| UTF-8 mit BOM | Für Kompatibilität mit Notepad, Excel |
| Windows-1251 | Für "alte Schule", lokale Programme auf Russisch |
| ASCII | Für Dateien mit nur englischem Text |
| UTF-16 | Für spezielle Fälle, exotische Anwendungen |
Hilfreiche "Tricks" und Tipps
Wie finde ich das Encoding einer Datei heraus?
- Spezielle Editoren (Notepad++, Visual Studio Code) erkennen und zeigen oft das Encoding an.
- Wenn kein BOM vorhanden ist und alles "bereichert" aussieht, aber die Buchstaben falsch sind — dann stimmt wahrscheinlich das Encoding nicht überein.
Lässt sich die Erkennung des Encodings automatisieren?
- In .NET gibt es keinen "Zauberstab", der 100% das Encoding jeder Datei bestimmt. Normalerweise gilt: wenn BOM vorhanden ist, ist es eindeutig UTF mit BOM; wenn nicht, muss man anhand des Inhalts raten oder verschiedene Varianten probieren.
Was tun, wenn ein Teil der Zeilen korrekt gelesen wird und ein Teil "mojibake"?
- Vielleicht ist die Datei "gemischt" oder beschädigt. Prüfe, ob die Datei von verschiedenen Programmen geschrieben wurde.
6. Typische Fehler und wie man sie vermeidet
Zum besseren Verständnis schauen wir uns häufige Fehler an:
Falsches Quell-Encoding. Wenn du denkst, die Datei sei UTF-8, sie aber tatsächlich Windows-1251 ist — bekommst du statt Kyrillisch eine "Leiter" von Zeichen. Prüfe die Quell-Encoding; bei Unsicherheit öffne die Datei in Notepad++ oder ähnlichen Editoren, die das tatsächliche Encoding anzeigen.
BOM am falschen Ort. Manchmal bricht das Hinzufügen von BOM das Parsing, manchmal führt das Fehlen von BOM auf der anderen Seite zu falscher Erkennung.
Die komplette Datei in den Speicher lesen. Bei großen Dateien lies zeilenweise — sonst frisst das Programm bei großen Textbeständen den gesamten RAM.
Schreiben ohne Angabe des Encodings. Standardmäßig verwendet StreamWriter UTF-8 ohne BOM. Wenn du eine andere Variante willst — gib das Encoding explizit an.
Falsche Verwendung von GetEncoding. Wenn der String falsch ist, z.B. "utf8" statt "utf-8", bekommst du eine Exception. Verwende korrekte Namen (oder Codes, z.B. 1251).
GO TO FULL VERSION