Mojibake unter Windows entsteht nicht, weil Japanisch schwierig ist. Fast immer liegt die Ursache darin, dass dieselbe Bytefolge mit einer anderen Zeichenkodierung gelesen wurde, oder dass das Ergebnis eines solchen Fehllesens mit einer weiteren Kodierung gespeichert wurde.
Besonders wenn Windows und Linux aufeinandertreffen, bleiben auf der Windows-Seite mehrere Kontexte bestehen — CP932, UTF-8, UTF-16, die Codepage der Konsole, Versionsunterschiede in PowerShell —, während die Linux-Seite meist von UTF-8 ausgeht. Dadurch treten zuvor unsichtbare Annahmefehler schlagartig zutage.
Es geht hier weniger um die Schwierigkeit der Japanisch-Verarbeitung als darum, ob man sich darüber im Klaren ist, unter welcher Annahme man Bytes behandelt. Dieser Artikel ordnet die Zeichenkodierung unter Windows aus der Perspektive „Warum entsteht Mojibake” ein und fasst praxisnah die Punkte zusammen, an denen sich Unfälle häufen, sobald Linux ins Spiel kommt.
Zielgruppe sind Leserinnen und Leser, die unter Windows erstellte CSV-/Log-/Konfigurationsdateien an Linux weiterreichen — oder umgekehrt — und die Ursachenklärung sowie Wiederherstellung bei Mojibake selbst durchführen möchten. Kenntnisse einer bestimmten Sprache oder eines Frameworks werden nicht vorausgesetzt. Die Beispielbefehle verwenden iconv und PowerShell.
1. Was zuerst wichtig ist
Vorab nur die Kernpunkte: Wichtig sind die folgenden 6 Punkte.
- Mojibake ist kein Problem der „Zeichen”, sondern ein Problem der „Interpretation der Bytefolge”.
- Unter Windows koexistieren die Unicode-Welt und die Welt der Legacy-Codepages, und selbst auf einer einzigen Maschine unterscheiden sich die Annahmen je nach Kontext.
- Auf der Linux-Seite herrscht eine starke UTF-8-Annahme, sodass es leicht zu Unfällen kommt, wenn sich windowsseitiges CP932 oder UTF-16 einmischt.
- Die Stufe, in der nur die Anzeige verstümmelt ist, und die Stufe, in der bereits beschädigter Inhalt gespeichert wurde, sollten getrennt betrachtet werden.
- Es ist sicher, bei neuem Text UTF-8 als erste Wahl zu setzen und bestehende Legacy-Dateien bis zu einer expliziten Migrationsaufgabe unverändert zu lassen.
- Die Kodierung der Datei, die Kodierung des Editors, die Codepage der Konsole und das interne Zeichenfolgenformat der Anwendung sind verschiedene Dinge. Vermischt man sie, verläuft sich die Untersuchung.
Mit der Aussage „unter Windows kam es zu Mojibake” allein lässt sich die Ursache nicht bestimmen. Mindestens muss man trennen, welcher der folgenden Punkte nicht übereinstimmt.
- Die Kodierung der Datei selbst
- Die beim Speichern verwendete Kodierung
- Die Interpretation des Editors
- Die Input-/Output-Codepage der Konsole
- Das interne Zeichenfolgenformat der Anwendung
- Die Locale und angenommene Kodierung auf der Linux-Seite
1.1 Vorab: Begriffe
Abkürzungen, die im Text ohne weitere Erklärung vorkommen, fassen wir vorab kurz zusammen.
| Begriff | Vollständige Bezeichnung | Bedeutung in diesem Artikel |
|---|---|---|
| BOM | Byte Order Mark | Ein paar Bytes am Dateianfang als Kennzeichen. Sie teilen dem Leser mit, um welche Unicode-Kodierung es sich handelt; bei UTF-16 zeigen sie zusätzlich die Byte-Reihenfolge an. Bei UTF-8 ist es optional |
| Codepage | – | Der Mechanismus, mit dem Windows über eine Nummer festlegt, „mit welcher Legacy-Zeichenkodierung” interpretiert wird. CP932 des japanischen Windows ist eine dieser Nummern |
| ANSI | – | Bezeichnung unter Windows für die jeweils „aktive Codepage”. Die tatsächliche Bedeutung hängt von der Umgebung ab; in einer japanischen Umgebung ist es CP932 |
| Locale | – | Eine Einstellung, die Sprache, Region und Standardkodierung bündelt. Unter Linux wird sie über LANG oder LC_ALL angegeben und schließt, wie bei ja_JP.UTF-8, auch die Kodierung ein |
| WSL | Windows Subsystem for Linux | Der Mechanismus, um Linux unter Windows laufen zu lassen. Da die Annahmen von Windows- und Linux-Seite auf einer Maschine zusammentreffen, ist dies ein Ort, an dem die in diesem Artikel behandelten Unfälle leicht auftreten |
| ETL | Extract / Transform / Load | Die Verarbeitung, Daten zu entnehmen, umzuwandeln und zurückzuschreiben. Da dabei Dateien zwischenzeitlich erneut gelesen und wieder gespeichert werden, ist dies eine Stelle, an der sich die Kodierung ändert |
2. Was Mojibake tatsächlich ist
Was Mojibake tatsächlich ist, ist recht einfach.
- Eine Zeichenfolge wird mit einer Kodierung encodiert und dadurch zu einer Bytefolge
- Diese Bytefolge wird mit einer Kodierung decodiert und dadurch wieder zu einer Zeichenfolge
- Stimmen die Annahmen von Encode und Decode nicht überein, wird sie als andere Zeichenfolge gelesen
Speichert man zum Beispiel あ als UTF-8, ergibt sich folgende Bytefolge.
E3 81 82
Liest man diese Bytefolge als UTF-8, ergibt sich あ; liest man sie im Kontext von CP932, sieht man eine andere Zeichenfolge wie 縺�. Das ist Mojibake.
Wichtig ist: Hier ist nicht „das Japanische kaputtgegangen”, sondern lediglich die Interpretation derselben Bytes ist auseinandergelaufen.
Sehen wir uns auch die umgekehrte Richtung an. Speichert man あ als CP932, ergibt sich folgende Bytefolge.
82 A0
Versucht man, diese Bytefolge als UTF-8 zu lesen, sind weder 0x82 noch 0xA0 als gültiges UTF-8-Startbyte zulässig, sodass beide zu Ersatzzeichen werden und �� erscheint. Aus UTF-8-Sicht ist das von vornherein gar kein gültiges Zeichen.
Ein etwas längeres Beispiel zeigt die Eigenheit deutlicher. Speichert man 日本語 als CP932, ergibt sich folgende Bytefolge.
93 FA 96 7B 8C EA
Liest man das als UTF-8, ergibt sich etwa ���{��. Beachtenswert ist hier, dass allein das vierte Byte, 0x7B, unverändert als ASCII-Zeichen { durchrutscht. Da das zweite Byte von CP932 mitunter im ASCII-Bereich liegt, mischen sich in das verstümmelte Ergebnis Zeichen wie { oder \.
Das bedeutet: Je nach Richtung unterscheidet sich das Symptom.
| Tatsächliche Bytefolge | Annahme des Lesers | Erscheinungsbild |
|---|---|---|
| UTF-8 | CP932 | Es erscheinen halbwegs plausibel wirkende Kanji oder Katakana wie 縺 |
| CP932 | UTF-8 | Überwiegend Ersatzzeichen �, gelegentlich mit ASCII-Symbolen wie { durchmischt |
Man kann grob abschätzen: „Stehen unlesbare Kanji da, wird UTF-8 als CP932 gelesen.” „Sind es überwiegend Ersatzzeichen, wird CP932 als UTF-8 gelesen.” Diese Asymmetrie zu kennen, beschleunigt die Ursachenklärung.
2.1 Ist nur die Anzeige verstümmelt, lässt sich manches noch retten
Mojibake hat eine Stufe, auf der noch Rettung möglich ist. Sind zum Beispiel die ursprünglichen Bytes unverändert, lässt sich die Datei durch erneutes Öffnen mit der richtigen Kodierung mitunter wiederherstellen.
Gefährlich ist umgekehrt ein Ablauf wie dieser.
- Eine UTF-8-Datei wird fälschlich als CP932 gelesen
- Auf dem Bildschirm erscheint etwas wie
縺� - Die „so angezeigte Zeichenfolge” wird unverändert gespeichert
- Die ursprünglichen UTF-8-Bytes gehen verloren
Ist dieser Punkt erst erreicht, handelt es sich nicht mehr um einen bloßen Anzeigefehler, sondern um Datenverlust.
2.2 Noch gefährlicher: „nicht darstellbare Zeichen” in eine schmale Codepage zwingen
Ein weiterer klassischer Unfall entsteht, wenn eine Unicode-Zeichenfolge in eine Legacy-Codepage wie CP932 heruntergebrochen wird.
Enthält die Zeichenfolge zum Beispiel Zeichen, die in der Codepage der Gegenseite nicht existieren, geschieht Folgendes:
- Ersetzung durch
? - Einfügen des Ersatzzeichens
� - Umwandlung in ein ähnliches, aber anderes Zeichen
- Fehlschlag der Umwandlung
Diesen Unfall sollte man nicht nur an lesbar oder unlesbar messen, sondern daran, ob eine Hin- und Rückumwandlung wieder das Original ergibt. Ein einmal verlorenes Zeichen lässt sich auch mit späterer Kenntnis der richtigen Kodierung nicht wiederherstellen.
3. Warum es unter Windows besonders unübersichtlich wird
Windows ist nicht deshalb unübersichtlich, weil es einfach alt ist. Es liegt daran, dass die Welt von Unicode und die Welt der Legacy-Codepages bis heute nebeneinander existieren.
3.1 In der Windows-API koexistieren Unicode- und Codepage-Linien
Die Windows-API hat im Wesentlichen zwei Linien.
- Die
W-Familie: wide character. Behandelt Unicode als UTF-16 - Die
A-Familie: die sogenannte ANSI-Codepage-Linie
Das heißt, in Windows gibt es von Anfang an sowohl einen Weg „als Unicode behandeln” als auch einen Weg „über die jeweils aktive Codepage behandeln”. Deshalb unterscheiden sich die Annahmen selbst auf demselben Windows-System danach, welche API oder welches Tool durchlaufen wurde.
3.2 „Japanisch unter Windows” ist nicht eine einzige Sache
Im Umgang mit japanischem Text unter Windows vermischen sich in der Praxis häufig diese vier:
- CP932: kommt oft bei Legacy-Text von japanischem Windows vor
- UTF-8: nimmt bei neueren Textbeständen, im Web und in plattformübergreifenden Kontexten zu
- UTF-16LE: taucht auch heute noch ganz selbstverständlich im Kontext von Windows-Tools und -APIs auf
- Die Codepage der Konsole: eine eigene Ebene, die Ein-/Ausgabe von
cmd.exeund einigen Konsolentools betrifft
Wichtig ist hier: Nicht weil man chcp 65001 ausgeführt hat, wird eine Datei zu UTF-8. Die Codepage der Konsole zu ändern und was die Bytes einer bestehenden Datei tatsächlich sind, sind zwei getrennte Fragen.
Übrigens wird der Legacy-Text von japanischem Windows oft locker „Shift_JIS” genannt, aber in der Praxis verhindert der Name CP932 eher, dass das Gespräch abdriftet. Zumindest macht er klar, dass „von der windows-eigenen japanischen Legacy-Kodierung die Rede ist”.
3.3 Dateiname und Dateiinhalt sind getrennte Fragen
Wenn unter Windows ein japanischer Dateiname ganz normal angezeigt wird, neigt man zu dem Gedanken „dann wird auch der Inhalt in Ordnung sein”. Genau hier lauert die Gefahr.
- Die Ebene, die Pfad / Dateiname behandelt
- Die Ebene, die den Dateiinhalt liest
- Die Ebene, die in der Konsole anzeigt
Diese drei sind getrennt.
Ein japanischer Pfad lässt sich zum Beispiel problemlos verarbeiten, während der Dateiinhalt in CP932 gespeichert ist und auf der Linux-Seite als UTF-8 gelesen kaputtgeht. Umgekehrt kann der Dateiinhalt UTF-8 sein, während allein die Anzeige verstümmelt ist, weil die Codepage der Konsole nicht passt.
Als Bild sieht die Schichtbeziehung so aus.
flowchart LR
W["Schreiber<br/>App / Editor / Skript"] --> FB["Bytefolge der Datei<br/>nur dies ist Tatsache"]
FB --> R1["Leser A: Editor<br/>automatische Erkennung oder angegebene Kodierung"]
FB --> R2["Leser B: Konsole<br/>Ein-/Ausgabe-Codepage"]
FB --> R3["Leser C: Anwendungsintern<br/>Standardkodierung der Bibliothek"]
FB --> R4["Leser D: Linux-Seite<br/>UTF-8-Annahme gemäß Locale"]
R1 --> S1["nur die Anzeige verstümmelt<br/>wird beim erneuten Speichern zu Datenverlust"]
R2 --> S2["nur die Anzeige verstümmelt<br/>Datei bleibt unversehrt"]
R3 --> S3["Verarbeitungsergebnis kaputt<br/>pflanzt sich stromabwärts fort"]
R4 --> S4["Decode-Fehler oder Ersatzzeichen"]
Zwei Punkte sind entscheidend. Erstens: unterscheiden, ob die Bytefolge in der Mitte kaputt ist, oder der Leser rechts. Zweitens: Die vier rechten Punkte sind voneinander unabhängig, sodass eine Bestätigung bei einem Punkt keine Garantie für die anderen drei ist. Dass „in der Konsole lesbar, also auch im Editor in Ordnung” nicht gilt, liegt genau an dieser Struktur.
3.4 Auch die Standardwerte von PowerShell und Begleitwerkzeugen sind nicht aufeinander abgestimmt
Ein unauffälliger Unfallverstärker unter Windows ist, dass dasselbe „ich habe Text geschrieben” je nach Weg unterschiedliche Ausgabe-Bytes erzeugt.
Besonders zu beachten ist Folgendes:
- Windows PowerShell 5.1 hat keine durchgängig konsistente Standardkodierung
- Manche Cmdlets und Umleitungen erzeugen UTF-16LE
- Auf anderen Wegen wird die aktive ANSI-Codepage verwendet
- PowerShell 7 und neuer verwendet standardmäßig UTF-8 ohne BOM
Das heißt: Allein aus „mit PowerShell erzeugter Text” lässt sich die Kodierung nicht bestimmen. Man muss wissen, mit welcher Version, welchem Cmdlet und welchem Schreibweg gearbeitet wurde.
Welcher Weg welche Bytes erzeugt, ist im Microsoft-Learn-Artikel about_Character_Encoding zusammengestellt. Die gängigsten davon:
| Schreibweg | Standard in Windows PowerShell 5.1 | Standard in PowerShell 7 |
|---|---|---|
Out-File, >, >> |
UTF-16LE (mit BOM) | UTF-8 ohne BOM |
Set-Content, Add-Content (neu oder leere Datei) |
ANSI = aktive Codepage. In japanischer Umgebung CP932 | UTF-8 ohne BOM |
Export-Csv |
ASCII. Nicht-ASCII-Zeichen entfallen | UTF-8 ohne BOM |
Export-Clixml, New-ModuleManifest |
UTF-16LE | UTF-8 ohne BOM |
New-Item -Type File -Value |
UTF-8 ohne BOM | UTF-8 ohne BOM |
Start-Transcript |
UTF-8 mit BOM | UTF-8 ohne BOM |
Auch beim Lesen gibt es Unterschiede. Beim Lesen einer Datei ohne BOM geht Get-Content unter 5.1 von ANSI aus, während Import-Csv und Select-String von UTF-8 ausgehen. Innerhalb derselben Sitzung sind die Annahmen also unterschiedlich.
Praktisch am stärksten schmerzt hier, dass bei demselben „Text geschrieben” Out-File UTF-16LE, Set-Content dagegen CP932 erzeugt. Das in 4.3 genannte „binär wirkende Text mit massenhaft NUL-Bytes” stammt meist aus dem Standardverhalten von > oder Out-File.
Ein weiterer Punkt: Auch mit -Encoding UTF8 erzeugt 5.1 eine Datei mit BOM. Möchte man unter 5.1 UTF-8 ohne BOM schreiben, muss man auf .NET zurückgreifen.
# UTF-8 ohne BOM unter Windows PowerShell 5.1 schreiben
$text = "日本語を含む本文"
[System.IO.File]::WriteAllText(
"C:\work\output.txt", $text,
(New-Object -TypeName System.Text.UTF8Encoding -ArgumentList $false))
Dass das Argument von UTF8Encoding auf $false gesetzt wird, ist die Angabe, kein BOM anzuhängen. Unter PowerShell 7 erzielt -Encoding utf8NoBOM dasselbe Ergebnis.
4. Typische Unfälle im Zusammenspiel mit Linux
Was unter Windows allein irgendwie funktionierte, bricht nicht selten in dem Moment zusammen, in dem Linux ins Spiel kommt. Der Grund ist einfach: Auf der Linux-Seite herrscht eine starke UTF-8-Annahme.
4.1 Windows speichert Text als CP932, Linux liest ihn als UTF-8
Der mit Abstand häufigste Unfall.
- Eine Legacy-App unter Windows oder ein alter Betriebsablauf schreibt CSV / TXT / Log in CP932
- Skripte und Tools auf der Linux-Seite lesen gemäß Locale mit UTF-8-Annahme
- Das Ergebnis: Decode-Fehler,
�, oder unverständliche Zeichenfolgen
Hier trägt nicht das Linux-Tool die Schuld — die eigentliche Ursache ist, dass den empfangenen Bytes keine Absprache über ihre Kodierung mitgegeben wurde.
4.2 Windows behandelt unter Linux / VS Code erzeugtes UTF-8 ohne BOM als ANSI
Auch die umgekehrte Richtung kommt vor.
- Unter Linux oder in VS Code wird ein Skript / eine Konfiguration / eine Textdatei als UTF-8 ohne BOM erstellt
- Windows PowerShell 5.1 oder ein Legacy-Tool behandelt die BOM-lose Datei als Codepage auf der ANSI-Seite
- Nur die Zeilen mit japanischem oder anderem Non-ASCII-Text gehen kaputt
Hier wird oft UTF-8 die Schuld gegeben, tatsächlich liegt die Ursache aber darin, dass sich ein Leser, der BOM-loses UTF-8 nicht korrekt erkennt, in die Kette mischt.
4.3 Windows schreibt UTF-16LE, und auf der Linux-Seite „sieht es nicht wie Text aus”
Auch das kommt recht häufig vor.
- Manche Ausgaben von Windows PowerShell 5.1 oder ein Legacy-Tool schreiben UTF-16LE
- Text-Tools auf der Linux-Seite erwarten einen UTF-8-1-Byte-Stream
- Das Ergebnis ist „binär wirkender Text” mit massenhaft eingemischten NUL-Bytes
UTF-16LE an sich ist nicht schlecht. Es passt aber oft nicht zur Annahme, es direkt in Linux-Textverarbeitungs-Tools weiterzuleiten.
4.4 Auch die BOM-Anwesenheit verursacht Reibung
Das BOM ist nicht die Kodierung selbst, wirkt sich in der Praxis aber deutlich aus.
- Manchen windowsseitigen Tools hilft ein BOM
- Manche linuxseitigen Tools behandeln das BOM als überflüssige führende Bytes
- Das Ergebnis: nur die erste Spalte oder der Anfang der ersten Zeile geht kaputt, unsichtbarer Müll erscheint, Vergleichsergebnisse verschieben sich
Besonders bei UTF-8 gilt: UTF-8 mit BOM und UTF-8 ohne BOM sind unterschiedliche Bytes. Mit „wir haben auf UTF-8 umgestellt” ist eine Betriebsregel erst zur Hälfte festgelegt.
4.5 Sich auf das Erscheinungsbild der Konsole zu verlassen führt in die Irre
Beim Übergang zwischen Windows und Linux ist noch etwas anderes gefährlich: die Konsole.
- Die Windows-Konsole besitzt Input-/Output-Codepages
- Linux-Terminals laufen meist unter der Annahme einer UTF-8-Locale
- Über WSL, SSH, Container und CI vervielfachen sich die Anzeigewege
Urteilt man in diesem Zustand „in der Konsole lesbar, also ist die Datei in Ordnung” oder „in der Konsole verstümmelt, also ist die Datei kaputt”, liegt man leicht daneben. Ob das Sichtbare kaputt ist und ob die gespeicherten Bytes kaputt sind, sollte man getrennt prüfen.
4.6 Die typischen Unfälle in Tabellenform
| Situation | Tatsächliche Bytes | Annahme des Lesers | Typisches Symptom |
|---|---|---|---|
| Von einer Legacy-Windows-App gespeicherte CSV | CP932 | Linux-Seite nimmt UTF-8 an | �, Decode-Fehler, unverständliches Japanisch |
| Unter Linux / VS Code erstellte Datei | UTF-8 ohne BOM | Windows PowerShell 5.1 behandelt sie als ANSI | Nur die japanischen Zeilen gehen kaputt |
| Manche Ausgabe von Windows PowerShell 5.1 | UTF-16LE oder ANSI | Linux-Seite erwartet UTF-8-Text | NUL-Bytes mischen sich ein, binärähnliches Verhalten |
| UTF-8-Datei mit BOM | UTF-8 + BOM | Unix-Tools nehmen reines UTF-8 an | Nur die erste Spalte kaputt, überflüssige Zeichen |
| Man vertraut allein der Konsolenanzeige | Datei und Konsole folgen unterschiedlichen Annahmen | Untersuchende Person urteilt allein nach der Anzeige | Die Ursachenklärung geht fehl |
5. Die Mojibake-Untersuchung mit diesen 4 Fragen vorantreiben
Hängt die Mojibake-Untersuchung fest, kommt man am schnellsten voran, wenn man zu diesen 4 Fragen zurückkehrt.
5.1 Was sind die ursprünglichen Bytes?
Zuerst sollte man betrachten, „welche Bytes diese Datei jetzt tatsächlich hat”. Man braucht die Einstellung, Bytes zu betrachten, nicht das Erscheinungsbild.
- Ist es UTF-8?
- UTF-8 mit BOM?
- CP932?
- UTF-16LE?
- Wurde die Datei zwischenzeitlich erneut gespeichert und dadurch zu etwas anderem?
5.2 Wer hat zuerst geschrieben, unter welcher Annahme?
Als Nächstes wird „der ursprüngliche Schreiber” bestimmt.
- Eine Legacy-App unter Windows?
- PowerShell 5.1 oder 7?
- Ein Linux-Skript?
- VS Code?
- Ein Export aus Excel?
- Irgendeine Middleware / ein Batch / eine CI?
Bleibt das unklar, wird die Kodierungsbestimmung zum Glücksspiel.
5.3 Wer liest jetzt, unter welcher Annahme?
Neben dem Schreiber braucht man auch die Annahme des Lesers.
- Erkennt der Editor automatisch?
- Achtet PowerShell auf das BOM?
- Behandelt die Linux-Seite die Datei gemäß Locale als UTF-8?
- Verwendet die Bibliothek ihre Standardkodierung?
- Wird
Encoding.UTF8odercp932explizit angegeben?
Mojibake entsteht fast immer genau hier.
5.4 Wurde der fehlgelesene Inhalt bereits gespeichert?
Zuletzt prüft man, ob der Schaden bei der Anzeige stehen geblieben ist.
- Sind die Bytes noch die ursprünglichen?
- Hat jemand den verstümmelt aussehenden Inhalt gespeichert?
- Sind
?oder�in den Diff eingegangen? - Wurde der gesamte Text mit einer anderen Kodierung neu geschrieben?
Sind diese 4 Fragen beantwortet, ist die Ursache meist sichtbar.
6. Wie man eine beschädigte Datei repariert
Ist die Ursache geklärt, folgt die Wiederherstellung. Zuerst entscheidet sich hier, ob die ursprünglichen Bytes noch vorhanden sind.
- Die ursprünglichen Bytes sind noch vorhanden: Mit der richtigen Kodierung erneut lesen und mit der gewünschten Kodierung wieder ausgeben — dann lässt sich die Datei zurückholen. Das ist das Vorgehen dieses Kapitels
- Der fehlgelesene Inhalt wurde bereits gespeichert: Es bleibt nur die Wiederherstellung aus einem Backup oder der Git-Historie. Zu Ersatzzeichen
�oder?gewordene Zeichen lassen sich auch bei Kenntnis der richtigen Kodierung nicht wiederherstellen
Deshalb sollte man als Allererstes eine Kopie des Arbeitsobjekts anlegen. Die Umwandlung erfolgt an der Kopie; die Originaldatei bleibt unangetastet.
6.1 Auf der Linux-Seite: iconv
Um eine CP932-Datei nach UTF-8 zu bringen, ist iconv die naheliegendste Wahl.
# CP932 -> UTF-8
iconv -f CP932 -t UTF-8 input.csv > output.csv
Ist die Quellkodierung falsch angegeben, bricht die Umwandlung mittendrin so ab:
iconv: illegal input sequence at position 0
Dass der Vorgang abbricht, ist selbst schon eine Information: „Das ist nicht diese Kodierung.” Es lohnt sich also, verschiedene Kandidaten durchzuprobieren. Bricht die Umwandlung dagegen bei keiner Angabe ab, besteht die Möglichkeit, dass die Datei nur aus ASCII besteht.
Beim Umwandeln von UTF-16LE nach UTF-8 verwendet man -f UTF-16LE. Gibt man bei einer Datei mit BOM jedoch ausdrücklich -f UTF-16LE an, kann das BOM als das eine Zeichen U+FEFF in der Ausgabe verbleiben. Möchte man den Umgang mit dem BOM iconv selbst überlassen, verwendet man -f UTF-16 und prüft nach der Umwandlung unbedingt das erste Zeichen.
6.2 Auf der Windows-Seite: PowerShell
Ab PowerShell 6.2 lässt sich -Encoding direkt eine Codepage-Nummer übergeben. CP932 ist 932.
# PowerShell 6.2 oder neuer. CP932 -> UTF-8 ohne BOM
Get-Content -Path .\input.csv -Encoding 932 |
Set-Content -Path .\output.csv -Encoding utf8NoBOM
Umgekehrt, wenn eine unter Linux erzeugte UTF-8-Datei an eine Gegenseite weitergegeben werden soll, die nur CP932 lesen kann:
Get-Content -Path .\input.csv -Encoding utf8 |
Set-Content -Path .\output.csv -Encoding 932
Diese Schreibweise hat allerdings zwei Nebenwirkungen.
Get-Contentteilt zeilenweise auf, undSet-Contentfügt hinter jeder Zeile wieder einen Zeilenumbruch ein. Das heißt, die Zeilenumbrüche werden vereinheitlicht- Fehlt am Ende der Originaldatei ein Zeilenumbruch, erscheint in der Ausgabe trotzdem einer
Sollen die Bytes einschließlich der Zeilenumbrüche unverändert erhalten bleiben, behandelt man die Datei als Ganzes, ohne sie in Zeilen aufzuteilen.
# CP932 -> UTF-8 ohne BOM, Zeilenumbrüche unverändert erhalten
$text = [System.IO.File]::ReadAllText(
"C:\work\input.csv", [System.Text.Encoding]::GetEncoding(932))
[System.IO.File]::WriteAllText(
"C:\work\output.csv", $text,
(New-Object -TypeName System.Text.UTF8Encoding -ArgumentList $false))
GetEncoding(932) lässt sich unter Windows PowerShell 5.1 direkt verwenden. Wirft dies unter PowerShell 7 in Ihrer Umgebung eine Ausnahme, führen Sie vorher einmal Folgendes aus.
[System.Text.Encoding]::RegisterProvider(
[System.Text.CodePagesEncodingProvider]::Instance)
Ob ein BOM angehängt wird, legt man wie in 7.1 nach den Bedürfnissen der Gegenseite fest. Setzt man im obigen Beispiel das Argument von UTF8Encoding auf $true, entsteht eine Datei mit BOM.
6.3 Was man nach der Umwandlung unbedingt prüfen sollte
Die Umwandlung ist nicht schon damit erledigt, dass „kein Fehler aufgetreten ist”. Mindestens sollte man Folgendes prüfen.
- Lassen sich 2–3 repräsentative japanische Zeilen korrekt lesen?
- Haben
?oder�zugenommen? Ist das der Fall, ist dieses Zeichen bereits verloren - Hat sich die Zeilenzahl verändert?
- Entsprechen BOM und Zeilenumbruch der Erwartung der Gegenseite?
- Hat sich die Dateigröße extrem verändert? Beim Wechsel von CP932 zu UTF-8 wächst der japanische Anteil von 2 auf 3 Bytes, sodass eine leichte Größenzunahme normal ist
Besonders der zweite Punkt ist wichtig. Bricht man UTF-8 mit Zeichen, die in CP932 nicht existieren, auf CP932 herunter, geht zwangsläufig Information verloren. Prüfen Sie wie in 2.2 beschrieben, ob eine Hin- und Rückumwandlung wieder das Original ergibt.
6.4 Massenumwandlung als eigene „Migrationsaufgabe” abtrennen
Zuletzt noch zum Betrieb. Eine einzelne beschädigte Datei zu reparieren und ein gesamtes Repository von CP932 auf UTF-8 umzustellen, sind unterschiedliche Aufgaben. Zweiteres sollten Sie, wie in 7.2 dieses Artikels beschrieben, nicht beiläufig im Rahmen einer normalen Funktionsänderung erledigen, sondern als eigenständige Migrationsaufgabe planen.
7. Betriebsregeln zur Unfallvermeidung
Von hier an geht es um die Praxis. Bei Projekten, die Windows und Linux verbinden, senkt es die Unfallquote deutlich, die folgenden Regeln vorab festzulegen.
7.1 Neue Dateien standardmäßig auf UTF-8 setzen
Für neue Textdateien ist es unbedenklich, zunächst UTF-8 als erste Wahl zu setzen. Hier darf man aber nicht stehen bleiben. Auch der Umgang mit dem BOM muss mitentschieden werden.
Empfehlenswert ist diese Festlegung:
- Text, der überwiegend auf der Linux-Seite gelesen wird: standardmäßig UTF-8 ohne BOM
- Skripte, die von Legacy-Tools unter Windows oder Windows PowerShell 5.1 gelesen werden: BOM-Vorhandensein explizit nach den Bedürfnissen der Gegenseite festlegen
- Gibt es eine klare Gegenseite, die UTF-16LE benötigt, diese Anforderung als Vorgabe schriftlich festhalten
Schreibt man nur „vereinheitlicht auf UTF-8”, gibt es später Streit ums BOM.
7.2 Bestehende Legacy-Dateien bis zur expliziten Migrationsaufgabe unverändert lassen
Ist eine bestehende Datei in CP932, ist es sicherer, sie nicht beiläufig im Rahmen einer normalen Funktionsänderung nach UTF-8 umzustellen.
Betrieblich ist diese Form sicher:
- Bestehende Dateien behalten ihre ursprüngliche Kodierung / ihr BOM / ihre Zeilenumbrüche
- Kodierungsänderungen werden als eigene Migrationsaufgabe abgetrennt
- Erst nach Prüfung von Umwandlungsziel, Auswirkungsbereich und nachgelagerten Konsumenten erfolgt die Massenumwandlung
Viele Mojibake-Unfälle beginnen mit einem wohlmeinenden „mal eben UTF-8 umstellen”.
7.3 Kodierung als Teil der Schnittstelle behandeln
Bei CSV, TXT, Log, Konfigurationsdateien und einfachen Protokollen ist nicht nur der Inhalt, sondern die Kodierung selbst Teil der Schnittstelle.
Als Vorgabe sollte mindestens Folgendes festgehalten werden:
- Ist diese Datei UTF-8 / CP932 / UTF-16LE?
- Trägt sie im Fall von UTF-8 ein BOM?
- Sind die Zeilenumbrüche LF oder CRLF?
- Wer ist Producer / Consumer, Linux oder Windows?
- Speichert ein zwischengeschalteter Batch oder ETL sie erneut?
„Wir übergeben es als Text” ist keine Spezifikation.
7.4 Standardwerten nicht vertrauen, beim Schreiben explizit angeben
Sowohl im Code als auch im Skript ist es sicherer, die Kodierung explizit anzugeben.
Gefährlich sind Gedankengänge wie diese:
- Mit dem Standard speichern
- Wird schon irgendwie zum Betriebssystem passen
- War in der Konsole lesbar, also wird die Datei schon in Ordnung sein
- Es gibt ja automatische Erkennung, also wird es schon passen
Standardwerte unterscheiden sich ganz gewöhnlich zwischen Windows / Linux, PowerShell 5.1 / 7, Editor und Laufzeitumgebung. Ohne explizite Angabe funktioniert es leicht nur zufällig.
7.5 Konsole und Datei getrennt prüfen
Eine unauffällig, aber sehr wirksame Regel ist diese.
- Prüfung der Anzeige in der Konsole
- Prüfung durch erneutes Öffnen der Datei
Diese beiden trennt man.
Auch wenn chcp oder die Terminalanzeige stimmen, bedeutet das nichts, wenn die gespeicherte Datei eine andere Kodierung hat. Umgekehrt kann die Datei einwandfrei sein, während nur die Anzeige verstümmelt ist, weil die Anzeige-Codepage der Konsole nicht passt.
7.6 Git repariert die Kodierung nicht
Unauffällig, aber wichtig.
Git verfolgt grundsätzlich nur Bytes. Das heißt, auch kaputte Bytes werden gewissenhaft genauso in die Historie übernommen.
Tritt daher einer dieser Fälle auf,
- ein riesiger Diff erscheint, obwohl nichts geändert wurde
- nur die japanischen Zeilen zeigen rätselhafte Diffs
- nur die erste Zeile hat sich geändert
- Zeilenumbruch und Kodierung ändern sich gemeinsam
sollte man eher einen Re-Encoding-Unfall vermuten als eine inhaltliche Änderung.
8. Die Mindest-Checkliste
Hier eine Checkliste, die es sich lohnt, bei Projekten mit Windows-Linux-Mischbetrieb von Anfang an festzulegen.
8.1 Vor der Bearbeitung
- Welche Kodierung hat diese Datei aktuell?
- Gibt es ein BOM?
- Sind die Zeilenumbrüche LF oder CRLF?
- Wurden 2–3 repräsentative japanische Zeilen notiert?
- Ist bekannt, ob Linux- oder Windows-Seite der endgültige Konsument ist?
8.2 Während der Bearbeitung
- Wird beim Schreiben von der Standardkodierung abhängig gearbeitet?
- Wird dem automatischen Erkennen beim Speichern vertraut?
- Werden PowerShell- oder Shell-Umleitungswege unbedacht genutzt?
- Beruhigt man sich nur damit, dass „die Anzeige lesbar ist”?
8.3 Nach der Bearbeitung
- Wurde nach dem Speichern erneut geöffnet und geprüft?
- Sind repräsentative Zeilen sowohl auf der Linux- als auch auf der Windows-Seite unverändert?
- Haben
?oder�im Diff zugenommen? - Ist nur die erste Zeile oder erste Spalte kaputt?
- Ist der Diff ein reiner BOM- oder Zeilenumbruch-Unterschied ohne inhaltliche Änderung?
8.4 Was als Migrationsaufgabe gehört
- Massenumwandlung von CP932 nach UTF-8
- Vereinheitlichung der UTF-8-BOM-Policy
- Bestandsaufnahme der Skripte, die von PowerShell 5.1 ausgehen
- Dokumentation der Textwege über CI / Container / WSL / SSH
- Vereinheitlichung der Speichereinstellungen von Editor / Formatter / Batch
9. Zusammenfassung
Fasst man das Windows-Kodierungsproblem in einem Satz zusammen, liegt sein Kern darin, dass die Welt von Unicode und die Welt der Legacy-Codepages bis heute nebeneinander bestehen.
Und dass sich Unfälle im Zusammenspiel mit Linux häufen, liegt daran, dass die Linux-Seite meist von UTF-8 ausgeht, sodass windowsseitiges CP932 und UTF-16, die Konsolen-Codepage und Versionsunterschiede in PowerShell schlagartig zutage treten.
Diese 5 Punkte sollte man sich merken:
- Mojibake ist eine auseinanderlaufende Byte-Interpretation
- Anzeigefehler und Datenverlust sind unterschiedliche Dinge
- Unter Windows sollte man in getrennten Schichten denken: Datei / Editor / Konsole / API
- Für Text im Austausch mit Linux sollte UTF-8 die erste Wahl sein
- Die Umwandlung bestehender Legacy-Dateien sollte von der gewöhnlichen Wartung getrennt bleiben
Nimmt man „unter Windows kam es zu Mojibake” wörtlich, ist das Thema zu breit. Aber schneidet man es mit diesen
- Was sind die ursprünglichen Bytes?
- Wer hat wie geschrieben?
- Wer hat wie gelesen?
- Wurde bereits gespeichert?
4 Fragen zu, lässt sich das Thema gut ordnen.
Zeichenkodierung ist unauffällig, aber zwischen Windows und Linux ist sie der I/O-Vertrag selbst. Diesen Punkt nicht offenzulassen, ist die wirksamste Gegenmaßnahme.
10. Referenzen
Windows / Microsoft
- Code Pages - Win32 apps | Microsoft Learn
- Code Page Identifiers - Win32 apps | Microsoft Learn
- Unicode in the Windows API - Win32 apps | Microsoft Learn
- Console Code Pages - Windows Console | Microsoft Learn
- chcp | Microsoft Learn
- Use UTF-8 code pages in Windows apps | Microsoft Learn
PowerShell / VS Code
- about_Character_Encoding | Microsoft Learn
- Understanding file encoding in VS Code and PowerShell | Microsoft Learn
GNU / Linux-Locale
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Windows-Zeichenkodierung und Zeilenumbrüche - Die Grundlagen von Mojibake und CRLF/LF
Eine praxisnahe Einordnung der unter Windows leicht verwechselten Zeichenkodierungen Shift_JIS / UTF-8 / UTF-16, der Ursachen von Mojibak...
Prompting-Regeln gegen Mojibake-Unfälle mit Codex unter Windows
Praxisnahe Prompting-Regeln, damit Codex unter Windows japanische Dateien sicher handhabt: kein Speichern auf Verdacht, das bestehende En...
WMI/CIM aus C# und PowerShell verwenden — Praxisleitfaden für Hardwareinformationen, Prozessüberwachung und Remoteabfragen
WMI/CIM ist die Standardlösung, um die Seriennummer eines PCs auszulesen, freien Festplattenspeicher zu überwachen und den Start von Proz...
Praktischer Leitfaden für Gruppenrichtlinien (GPO) — Funktionsweise, Überprüfung der Anwendung und Abgrenzung zu Intune
Arbeiten Sie in einer AD-Umgebung, ohne wirklich zu wissen, was „per GPO verteilt“ bedeutet? Dieser Artikel erklärt aus praktischer Sicht...
Windows-Sicherheitsüberwachungsrichtlinien und Ereignisprotokolluntersuchung in der Praxis — Zur IT-Abteilung werden, die Ereignis 4625 lesen kann
Ein praktischer Leitfaden, um auf „Bitte prüfen Sie die Protokolle fehlgeschlagener Anmeldungen“ reagieren zu können. Er behandelt das Ve...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Technische Beratung und Design-Review
Bei Projekten, bei denen die Kodierungsannahmen für CSVs, Logs und Konfigurationsdateien zwischen Windows und Linux auseinanderlaufen, senkt eine vorab geklärte I/O-Vertragslage und Betriebsregelung die Unfallquote.
Windows-App-Entwicklung
In Windows-Fachanwendungen sind CP932 und UTF-8 häufig gemischt im Einsatz; den Umgang mit Zeichenkodierung fest ins Design aufzunehmen, wirkt sich direkt auf die Wartbarkeit aus.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Wodurch entsteht Mojibake unter Windows?
- Fast immer dadurch, dass dieselbe Bytefolge mit einer anderen Zeichenkodierung gelesen wurde, oder dass das Ergebnis eines solchen Fehllesens mit einer weiteren Kodierung gespeichert wurde. Speichert man etwa „あ“ als UTF-8 (Bytefolge E3 81 82) und liest diese Bytes im Kontext von CP932, erscheint eine andere Zeichenfolge wie „縺“. Es liegt nicht daran, dass Japanisch schwierig ist — die eigentliche Ursache ist, dass die Annahmen von Encode und Decode nicht übereinstimmen.
- Lässt sich eine bereits verstümmelte Datei wieder reparieren?
- Ist die ursprüngliche Bytefolge unverändert, lässt sie sich in manchen Fällen durch erneutes Öffnen mit der richtigen Kodierung wiederherstellen. Gefährlich wird es, wenn der fehlgelesene, verstümmelt aussehende Inhalt genau so gespeichert wird — ab diesem Punkt handelt es sich nicht mehr um einen Anzeigefehler, sondern um Datenverlust. Wird zudem eine Unicode-Zeichenfolge in eine schmale Codepage wie CP932 heruntergebrochen und dabei zu „?“ oder einem Ersatzzeichen, lässt sich das verlorene Zeichen später auch mit Kenntnis der richtigen Kodierung nicht mehr wiederherstellen.
- Macht chcp 65001 auch Dateien zu UTF-8?
- Nein. Die Codepage der Konsole zu ändern und was die Bytefolge einer bestehenden Datei tatsächlich ist, sind zwei getrennte Fragen. Unter Windows sind die Kodierung der Datei selbst, die Interpretation des Editors, die Input-/Output-Codepage der Konsole und das interne Zeichenfolgenformat der Anwendung jeweils eigenständige Dinge, die man getrennt betrachten muss. Der Schluss „in der Konsole lesbar, also ist auch die Datei in Ordnung“ trügt leicht — die Prüfung der Konsolenanzeige und die Prüfung durch erneutes Öffnen der Datei sollten getrennt erfolgen.
- Welche sicheren Regeln gelten für den Textaustausch zwischen Windows und Linux?
- Neue Dateien standardmäßig auf UTF-8 setzen und dabei auch den Umgang mit dem BOM festlegen. Text, der überwiegend auf der Linux-Seite gelesen wird, sollte grundsätzlich UTF-8 ohne BOM sein; liest ihn ein Legacy-Tool wie Windows PowerShell 5.1, wird das BOM explizit nach den Bedürfnissen der Gegenseite festgelegt. Bestehende CP932-Dateien sollten nicht beiläufig im Rahmen einer normalen Änderung umkodiert, sondern als eigene, ausdrückliche Migrationsaufgabe abgetrennt werden. Da bei CSV und Logs die Kodierung selbst Teil der Schnittstelle ist, senkt es die Unfallquote, Kodierung, BOM und Zeilenumbruch als Vorgabe schriftlich festzuhalten.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.