Windows-Zeichenkodierung und Zeilenumbrüche - Die Grundlagen von Mojibake und CRLF/LF

· · Windows, Zeichenkodierung, Mojibake, Zeilenumbrüche, UTF-8, CP932, PowerShell, Unicode

Bei Anfragen rund um Text unter Windows vermischen sich erstaunlich oft die folgenden Themen auf einmal.

  • Was der Unterschied zwischen Shift_JIS und UTF-8 ist
  • Warum Mojibake (Zeichensalat) entsteht
  • Was der Unterschied zwischen CRLF und LF ist
  • Warum eine Datei trotz Umstellung auf UTF-8 manchmal noch nicht lesbar ist
  • Warum dieselbe Datei im Editor, in der Konsole, in Excel und in Git unterschiedlich aussieht

Das liegt nicht daran, dass Japanisch schwierig wäre. Fast immer liegt die Ursache darin, dass dieselbe Byte-Folge unter einer anderen Annahme gelesen wurde, oder dass falsch gelesener Inhalt unverändert gespeichert wurde.

Hinzu kommt, dass unter Windows nach wie vor die Welt von Unicode und die Welt der Codepages nebeneinander existieren. Legt man dann noch BOM, Zeilenumbrüche, die automatische Erkennung des Editors, die Codepage der Konsole und die Zeilenumbruch-Konvertierung von Git darüber, wirkt das Thema schnell unübersichtlich.

Dieser Artikel ordnet für die Praxis die unter Windows häufig verwechselten Kodierungen Shift_JIS / UTF-8 / UTF-16, die Ursache von Mojibake, den Unterschied zwischen CRLF und LF sowie den Grund für die Verwirrung insgesamt ein.

Der Inhalt beruht auf öffentlich zugänglichen Informationen von Microsoft Learn, PowerShell, Git sowie W3C / Unicode mit Stand April 2026. Details finden Sie in den Quellen am Ende.

Zielgruppe und Voraussetzungen

Punkt Inhalt
Zielgruppe Entwickler und IT-Verantwortliche, die unter Windows Textdateien (CSV, Protokolle, Konfigurationsdateien, Quellcode) mit anderen Abteilungen, anderen Systemen oder der Linux-Seite austauschen
Vorkenntnisse Keine besonderen. Der Artikel ist so aufgebaut, dass er auch verständlich ist, wenn der Unterschied zwischen Byte-Folge und Zeichenkodierung noch nicht klar ist
Vorausgesetzte Umgebung Windows 10 / Windows 11. Bei PowerShell werden sowohl Windows PowerShell 5.1 als auch PowerShell 7 behandelt
Nicht behandelt Die Verwendung bibliotheksspezifischer APIs zur Kodierungsumwandlung, das Design von Schriftarten/Glyphen sowie Normalisierungen wie Halb-/Vollbreitenzeichen

Wenn es schnell gehen muss: Für den Gesamtüberblick genügen Kapitel 1 und 2, für die reine Ursachenabgrenzung Kapitel 3 und 8, und wer Betriebsregeln festlegen möchte, sollte direkt bei Kapitel 7 einsteigen.

Inhaltsverzeichnis

  1. Was zuerst wichtig ist
  2. Die Begriffe im Einzelnen betrachten
    • 2.1 Was Unicode / UTF-8 / UTF-16 / CP932 voneinander unterscheidet
    • 2.2 Wie man Shift_JIS und CP932 einordnet
    • 2.3 Die Fallstricke der Begriffe ANSI, Unicode und UTF-8N
    • 2.4 Was das BOM ist und warum es auch bei UTF-8 vorkommt
  3. Warum Mojibake entsteht
    • 3.1 Was Mojibake tatsächlich ist
    • 3.2 Anzeigefehler und Datenverlust sind zweierlei
    • 3.3 Nicht darstellbare Zeichen: einmal verloren, kommt nichts mehr zurück
  4. Die Unterschiede bei Zeilenumbruchzeichen
    • 4.1 CRLF / LF / CR
    • 4.2 Der Zeilenumbruch ist ein eigenes Thema, getrennt von der Zeichenkodierung
    • 4.3 \n und die Zeilenumbruch-Bytes in der Datei sind nicht zwangsläufig identisch
  5. Warum es unter Windows besonders leicht zu Verwirrung kommt
    • 5.1 Unicode und Legacy-Codepages existieren nebeneinander
    • 5.2 Die Bezeichnungen sind nicht einheitlich
    • 5.3 Bei reinem ASCII bleibt das Problem verborgen
    • 5.4 Dateiinhalt, Dateiname, Konsole und Quelldatei sind getrennte Ebenen
    • 5.5 BOM und Zeilenumbruch wirken auf noch einer weiteren Achse
    • 5.6 Tools ändern Dinge eigenmächtig
  6. Typische Unfallmuster
  7. Regeln, die in der Praxis Unfälle reduzieren
  8. Mojibake- und Zeilenende-Untersuchungen mit diesen 5 Fragen angehen
  9. Zusammenfassung
  10. Verwandte Artikel
  11. Quellen

1. Was zuerst wichtig ist

Vorweg die wichtigsten Punkte: Es sind diese sieben.

  • Eine Textdatei besteht nicht aus der Zeichenkette selbst, sondern aus Byte-Folge + Zeichenkodierung + Zeilenumbruch. Mitunter kommt noch ein BOM (Byte Order Mark, Byte-Reihenfolge-Markierung) hinzu.
  • Mojibake entsteht, wenn dieselbe Byte-Folge mit einer anderen Zeichenkodierung decodiert wird.
  • Zeilenumbruch-Probleme entstehen, wenn die Zeichenkodierung stimmt, aber die Annahme über die Zeilentrenner nicht übereinstimmt.
  • Unicode und UTF-8 bedeuten nicht dasselbe. Unicode betrifft den Zeichensatz, UTF-8 und UTF-16 betreffen die Kodierung, die daraus Bytes macht.
  • Was unter Windows „Shift_JIS“ genannt wird, sollte man in der Praxis eher als CP932 / die Windows-eigene Familie japanischer Codepages verstehen — so drifted das Gespräch weniger.
  • „Wir haben auf UTF-8 umgestellt“ ist als Spezifikation noch nicht ausreichend. Erst wenn auch das Vorhandensein eines BOM und der Zeilenumbruch festgelegt sind, wird daraus eine Betriebsregel.
  • Die Ursache der Verwirrung ist nicht Japanisch selbst, sondern dass mehrere Annahmen mit unterschiedlicher Geschichte auf demselben Windows-System weiterleben.

Beim Umgang mit Text unter Windows ist es der beste Ausgangspunkt, zunächst diese vier Punkte auseinanderzuhalten:

  1. Wie lautet die Byte-Folge dieser Datei
  2. Mit welcher Zeichenkodierung wurde sie geschrieben
  3. Mit welcher Zeichenkodierung wird sie gelesen
  4. Ist der Zeilenumbruch CRLF oder LF

Allein diese Trennung reduziert die Verwirrung erheblich.

2. Die Begriffe im Einzelnen betrachten

2.1 Was Unicode / UTF-8 / UTF-16 / CP932 voneinander unterscheidet

Zunächst lohnt es sich, die Begriffe einmal auseinanderzunehmen.

Begriff Was er bezeichnet Beispiel Häufige Verwechslung
Unicode Ein Rahmenwerk, das Zeichen durch Nummern darstellt U+3042 () Wird mit UTF-8 gleichgesetzt
UTF-8 Eine Zeichenkodierung, die Unicode in Bytes umsetzt E3 81 82 Wird für Unicode selbst gehalten
UTF-16LE Eine Zeichenkodierung, die Unicode in Bytes umsetzt 42 30 Wird mit der Menübezeichnung Unicode vermischt
CP932 Die japanische Legacy-Codepage von Windows 82 A0 Wird für vollkommen identisch mit Shift_JIS gehalten
CRLF / LF Die Bytes, die Zeilen trennen 0D 0A / 0A Wird für eine Art Zeichenkodierung gehalten
BOM (Byte Order Mark) Eine Kennungs-Byte-Folge am Dateianfang EF BB BF u. Ä. Wird für den Namen einer Zeichenkodierung selbst gehalten

Selbst bei einem einzigen Zeichen wie unterscheidet sich die Byte-Folge je nach Kodierung.

Zeichen: あ

UTF-8    : E3 81 82
CP932    : 82 A0
UTF-16LE : 42 30

Entscheidend ist, dass Zeichen und Byte-Folge zwei verschiedene Dinge sind. Eine Anwendung arbeitet auf dem Bildschirm scheinbar mit „Zeichen“, tauscht beim Speichern oder bei der Übertragung aber letztlich Bytes aus. Die meisten Unfälle passieren genau an dieser Umwandlungsgrenze.

2.2 Wie man Shift_JIS und CP932 einordnet

In der Praxis werden japanische Windows-Textdateien oft pauschal „Shift_JIS“ genannt. Im Gespräch funktioniert das, für die praktische Arbeit ist es aber etwas ungenau.

Wer japanischen Legacy-Text unter Windows präzise erfassen möchte, ist mit CP932 beziehungsweise der Windows-eigenen Familie japanischer Codepages sicherer beraten.

Wird das ungenau gehandhabt, driften Gespräche wie diese auseinander:

  • Man sagte „speichere als Shift_JIS“, das Gegenüber ging aber von Windows-seitigem CP932 aus
  • Auf der Linux-/macOS-Seite wurde die Datei als shift_jis behandelt, aber bei manchen Dateien mit Windows-Herkunft stimmt der Rückweg nicht
  • Man wurde gebeten, als ANSI zu speichern, aber welche Codepage das bedeutet, hängt von der Umgebung ab

Deshalb ist es in Spezifikationen und Untersuchungsnotizen sicherer, möglichst konkret zu schreiben:

  • Nicht Shift_JIS, sondern CP932
  • Nicht ANSI, sondern ACP (Active Code Page) / in japanischen Umgebungen üblicherweise CP932
  • Nicht Text, sondern konkret etwa UTF-8 ohne BOM, LF

2.3 Die Fallstricke der Begriffe ANSI, Unicode und UTF-8N

Rund um Windows sind auch die Wortbezeichnungen selbst eine Quelle der Verwirrung.

Besonders irreführend sind diese drei:

  • ANSI Taucht in der Windows-Oberfläche und in älteren Erklärungen auf, ist aber nicht ASCII. Meist meint es die aktive Codepage (ACP) der jeweiligen Maschine.
  • Unicode In manchen Editoren und Tools bedeutet der Menüpunkt Unicode tatsächlich UTF-16LE. „Ich habe es als Unicode gespeichert“ heißt also nicht zwingend UTF-8.
  • UTF-8N Kommt in manchen japanischsprachigen Editoren vor; es ist normalerweise eine UI-Bezeichnung, um UTF-8 ohne BOM zu kennzeichnen. Es ist kein offizieller Name einer Zeichenkodierung.

Kurz gesagt: Unter Windows bedeutet dasselbe Wort je nach Tool etwas anderes. Das ist der erste große Verwirrungspunkt.

2.4 Was das BOM ist und warum es auch bei UTF-8 vorkommt

BOM steht für Byte Order Mark (Byte-Reihenfolge-Markierung) und bezeichnet das Codepoint U+FEFF, das an den Anfang einer Datei oder eines Streams gesetzt wird. Wie der Name sagt, besteht seine ursprüngliche Aufgabe darin, die Byte-Reihenfolge anzuzeigen.

Da UTF-16 und UTF-32 Zeichen jeweils in Blöcken von 2 beziehungsweise 4 Bytes darstellen, muss dem Leser mitgeteilt werden, ob diese Blöcke „mit dem niedrigstwertigen Byte zuerst“ (Little Endian) oder „mit dem höchstwertigen Byte zuerst“ (Big Endian) angeordnet sind. Dafür wird das BOM an den Anfang gesetzt, und seine eigene Byte-Reihenfolge zeigt an, dass die gleiche Reihenfolge auch im weiteren Verlauf gilt.

Byte-Folge am Anfang Bedeutung
FF FE UTF-16 Little Endian
FE FF UTF-16 Big Endian
EF BB BF UTF-8

Hier stellt sich die Frage: UTF-8 arbeitet byteweise und hat eigentlich kein Reihenfolge-Problem — warum bekommt es dann trotzdem ein BOM?

Der Grund ist, dass das BOM bei UTF-8 nicht die Byte-Reihenfolge anzeigt, sondern als Signatur mit der Bedeutung „diese Datei ist UTF-8“ verwendet wird. Da UTF-8 mit ASCII kompatibel ist, lässt sich bei rein alphanumerischem Inhalt nicht erkennen, ob es sich um UTF-8 oder eine Legacy-Codepage handelt. Steht am Anfang EF BB BF, kann die lesende Seite entscheiden: „Das ist nicht die aktive Codepage, sondern UTF-8.“

Umgekehrt bedeutet das:

  • Vorteil des BOM: Die lesende Seite errät die Zeichenkodierung seltener falsch. Insbesondere Windows PowerShell 5.1 liest Skriptdateien ohne BOM als aktive Codepage, weshalb Skripte mit Nicht-ASCII-Zeichen ohne BOM kaputtgehen.
  • Nachteil des BOM: Am Anfang stehen 3 zusätzliche Bytes. Systeme, die das BOM nicht kennen, behandeln es so, als stünde am Anfang der ersten Zeile ein unsichtbares Zeichen. Genau daraus entstehen Unfälle wie ein nicht übereinstimmender Name in der ersten CSV-Kopfspalte oder eine #!-Zeile in einem Shell-Skript, die nicht erkannt wird.

Mit anderen Worten: Beim BOM in UTF-8 geht es nicht um „richtig oder falsch“, sondern um eine Einstellung, die davon abhängt, wer die Datei liest. Genau deshalb muss man, wie in 7.1 beschrieben, nicht nur „auf UTF-8 umstellen“, sondern auch festlegen, ob es „mit BOM“ oder „ohne BOM“ sein soll.

3. Warum Mojibake entsteht

3.1 Was Mojibake tatsächlich ist

Was Mojibake wirklich ist, ist ziemlich einfach.

  1. Eine Zeichenkette wird mit einer bestimmten Kodierung in Bytes umgewandelt
  2. Diese Bytes werden mit einer anderen Kodierung zurück in eine Zeichenkette umgewandelt
  3. Stimmen die Annahmen nicht überein, entsteht eine andere Zeichenkette

Speichert man beispielsweise als UTF-8, ergibt sich diese Byte-Folge:

E3 81 82

Liest man das als UTF-8, ergibt sich ; liest man es aber unter der Annahme CP932, erscheint eine andere Zeichenfolge wie 縺�. Kaputt ist hier nicht „das Japanische“, sondern die Decodier-Annahme.

Mojibake in einem Satz:

Dieselbe Byte-Folge wurde mit einer anderen Zeichenkodierung gelesen.

Mit UTF-8 kodieren und speichernAls UTF-8 decodierenAls CP932 decodierenZeichen あByte-Folge E3 81 82Nur das steckt in der DateiZeichen あ ── Annahme stimmt übereinAndere Zeichenfolge wie 縺 ── Annahme ist verschoben

Abbildung 1: An der Weggabelung ist der Dateiinhalt (die Byte-Folge) identisch. Der einzige Unterschied ist die Annahme, die die lesende Seite trifft

3.2 Anzeigefehler und Datenverlust sind zweierlei

Wichtig ist hier, das Stadium, in dem sich noch etwas retten lässt, von dem Stadium, in dem das kaum noch möglich ist, zu trennen.

Bei folgendem Ablauf lässt sich beispielsweise noch etwas retten:

  1. Eine UTF-8-Datei wird als CP932 geöffnet
  2. Auf dem Bildschirm erscheint etwas wie 縺�
  3. Es wurde noch nicht gespeichert

In diesem Stadium bleiben die ursprünglichen Bytes weiterhin UTF-8. Öffnet man erneut mit der richtigen Kodierung, kommt der Inhalt oft zurück.

Gefährlich ist dieser Ablauf:

  1. Eine UTF-8-Datei wird fälschlich als CP932 gelesen
  2. Der sichtbar kaputte Inhalt wird unverändert gespeichert
  3. Die ursprünglichen UTF-8-Bytes gehen verloren

An diesem Punkt handelt es sich nicht mehr um einen Anzeigefehler, sondern um Datenverlust.

Unter der Annahme CP932 öffnenErneut öffnenSo speichernAls UTF-8 gespeicherte DateiByte-Folge ist E3 81 82Auf dem Bildschirm erscheint 縺= Anzeigefehler. Die Bytes sind noch UTF-8Mit der richtigen Kodierung geöffnet, kommt der Inhalt zurückDer falsch gelesene Text wird als CP932 zurückgeschrieben= Datenverlust. Die ursprünglichen Bytes sind wegAuch wenn man später die richtige Kodierung erfährt, kommt nichts mehr zurück

Abbildung 2: Der Scheideweg ist genau der eine Schritt „erneut geöffnet oder gespeichert“. Das sollte bei jeder Untersuchung zuerst geklärt werden

In der Praxis ist es wichtig, „es ist Mojibake“ nicht als einen einzigen Satz stehen zu lassen, sondern mindestens diese zwei Fragen zu trennen:

  • Ist die Byte-Folge selbst noch korrekt
  • Wurde der falsch gelesene Inhalt bereits erneut gespeichert

3.3 Nicht darstellbare Zeichen: einmal verloren, kommt nichts mehr zurück

Eine weitere Gefahr besteht, wenn eine Unicode-Zeichenkette auf eine enge Codepage wie CP932 heruntergebrochen wird.

Enthält die Zeichenkette dabei Zeichen, die auf der Zielseite nicht existieren, passiert eines der folgenden Dinge:

  • Sie werden durch ? ersetzt
  • Ein Ersatzzeichen wird eingefügt
  • Die Umwandlung schlägt mit einem Fehler fehl
  • Sie werden auf ein ähnliches, nahe liegendes Zeichen abgebildet

Manche Emoji und erweiterte Kanji lassen sich beispielsweise nicht unverändert in CP932 überführen. Dieser Fall sollte nicht danach beurteilt werden, „ob es lesbar ist“, sondern danach, ob eine Hin- und Rückkonvertierung wieder zum Original führt.

Einmal verlorene Information kommt auch dann nicht zurück, wenn man die richtige Kodierung nachträglich erfährt.

4. Die Unterschiede bei Zeilenumbruchzeichen

4.1 CRLF / LF / CR

Auch Zeilenumbrüche sind Bytes.

  • CR = carriage return = 0D
  • LF = line feed = 0A
  • In Windows-Textdateien ist CRLF (0D 0A) traditionell üblich
  • Unter Linux/Unix ist LF (0A) verbreitet
  • Alleinstehendes CR taucht mitunter in älteren Kontexten wie dem klassischen Mac auf

In Tabellenform:

Zeilenumbruch Byte-Folge Hauptkontext
CRLF 0D 0A Klassische Windows-Textdateien, Legacy-Tools
LF 0A Linux / macOS / die meisten Entwicklungswerkzeuge
CR 0D Recht alte Legacy-Daten

4.2 Der Zeilenumbruch ist ein eigenes Thema, getrennt von der Zeichenkodierung

Das ist ein wichtiger Punkt.

Der Zeilenumbruch ist ein von der Zeichenkodierung getrenntes Thema.

Auch bei derselben UTF-8-Datei kann der Zeilenumbruch CRLF oder LF sein. Bei einem Inhalt aus A, Zeilenumbruch, B ändern sich die Bytes zum Beispiel so:

UTF-8 + LF   : 41 0A 42
UTF-8 + CRLF : 41 0D 0A 42

Das heißt, all das ist ganz normal möglich:

  • UTF-8, aber nur der Zeilenumbruch weicht ab
  • CP932, aber der Zeilenumbruch ist LF
  • UTF-16LE, aber der Zeilenumbruch ist CRLF

Wenn also „wir haben auf UTF-8 umgestellt, aber es passt immer noch nicht“ auftritt, liegt es manchmal tatsächlich nicht an der Zeichenkodierung, sondern allein daran, dass der Zeilenumbruch nicht übereinstimmt.

4.3 \n und die Zeilenumbruch-Bytes in der Datei sind nicht zwangsläufig identisch

Aus Programmierersicht ist genau das ein leiser Stolperstein.

Nur weil im Quellcode \n steht, heißt das nicht zwangsläufig, dass in der Datei nur 0A erscheint. Im Textmodus einer Sprache, einer Laufzeitumgebung oder einer I/O-API kann \n unter Windows in CRLF umgewandelt werden.

Das heißt, Folgendes kann auseinanderdriften:

  • die Zeilenumbruch-Notation im Quellcode
  • die Zeichenkette zur Laufzeit
  • die in der Datei gespeicherte Byte-Folge
  • der im Editor sichtbare Zeilenumbruch

Deshalb passiert der Unfall „ich dachte, ich hätte LF geschrieben, aber die Datei war CRLF“.

Moderne Editoren kommen mit reinem LF problemlos zurecht, aber Umgebungswerkzeuge, Legacy-Anwendungen und der operative Betrieb setzen vielfach noch CRLF voraus. Deshalb ist das Zeilenumbruch-Problem keine „Geschichte von früher“, sondern taucht auch heute noch ganz normal in der Praxis auf.

5. Warum es unter Windows besonders leicht zu Verwirrung kommt

5.1 Unicode und Legacy-Codepages existieren nebeneinander

Das ist der größte Grund, warum Windows kompliziert ist.

Unter Windows bestehen weiterhin

  • der Weg über Unicode
  • der codepage-basierte Weg

nebeneinander.

Neuere Anwendungen, das Web und plattformübergreifende Bestände tendieren zu UTF-8, während ältere CSVs, TXT-Dateien, Protokolle, der Excel-Bereich und die Anbindung von Fachanwendungen weiterhin CP932 verwenden. Darüber hinaus taucht bei manchen Ausgaben und rund um bestimmte APIs auch ganz normal UTF-16LE auf.

Mit anderen Worten: In einem einzigen Windows-System leben mehrere Textkulturen zusammen.

5.2 Die Bezeichnungen sind nicht einheitlich

Was die Verwirrung noch verstärkt, ist weniger die Technik selbst als die Unstimmigkeit der Bezeichnungen.

  • Man sagt Shift_JIS, tatsächlich ist es CP932
  • Man sagt ANSI, tatsächlich ist es die aktive Codepage
  • Man sagt Unicode, tatsächlich ist es UTF-16LE
  • Man sagt UTF-8, aber ob mit oder ohne BOM ist gar nicht festgelegt
  • Editor-eigene Bezeichnungen wie UTF-8N tauchen auf

Bleibt das vage, wirkt das Gespräch, als verstünde man sich, während die tatsächlichen Zustände gar nicht übereinstimmen.

5.3 Bei reinem ASCII bleibt das Problem verborgen

Auch das ist gewichtig.

Da UTF-8 mit dem ASCII-Bereich kompatibel ist, lässt sich eine Datei mit nur alphanumerischen Zeichen und Symbolen selbst unter einer falschen Annahme „irgendwie lesen“. Auch auf der CP932-Seite bleibt der ASCII-äquivalente Bereich meist unauffällig, sodass das Problem nicht sichtbar wird.

Das Ergebnis sieht dann so aus:

  • Eine rein englischsprachige Konfigurationsdatei sieht einwandfrei aus
  • Sobald eine Zeile Japanisch hinzukommt, bricht es
  • Ein Problem, das lange verborgen war, entzündet sich zum ersten Mal während des Betriebs

Deshalb wirken Kodierungsunfälle oft wie „es lief bis gestern noch, und heute geht es plötzlich nicht mehr“. Tatsächlich war die Mine meist schon vorher vorhanden — sie wurde erst in dem Moment sichtbar, als ein Nicht-ASCII-Zeichen auftauchte.

5.4 Dateiinhalt, Dateiname, Konsole und Quelldatei sind getrennte Ebenen

Unter Windows verliert man leicht den Überblick, wenn man Folgendes zusammen als „die Zeichenkodierung“ bezeichnet.

  • Dateiname / Pfad
  • Dateiinhalt
  • Anzeige in der Konsole
  • Die Zeichenkodierung der Quelldatei selbst
  • Das Format der Zeichenkette zur Laufzeit
  • Anzeige in der Zwischenablage oder in GUI-Elementen

Ein japanischer Dateiname kann beispielsweise ganz normal aussehen, während der Dateiinhalt trotzdem in CP932 gespeichert ist. Umgekehrt kann die Datei selbst UTF-8 sein, während allein die Anzeige kaputt wirkt, weil die Codepage der Konsole nicht passt.

Auch ein Befehl wie chcp 65001 wirkt grundsätzlich nur auf die Annahme der Konsolenseite — er ändert nicht die Bytes bestehender Dateien.

Selbst wenn die Quelldatei UTF-8 ist, muss außerdem die zur Laufzeit geschriebene Protokolldatei nicht zwangsläufig UTF-8 sein. Man muss sich jedes Mal klarmachen, von der Kodierung welcher Ebene gerade die Rede ist.

Übrigens kann unter japanischem Windows \ als Yen-Zeichen erscheinen, was sich ebenfalls leicht mit dem Thema Zeichenkodierung vermischt. In den meisten Fällen ist das jedoch ein Problem der Anzeigeschriftart bzw. der Glyphen — die Bedeutung als Pfadtrenner oder Escape-Zeichen hat sich dadurch nicht geändert.

5.5 BOM und Zeilenumbruch wirken auf noch einer weiteren Achse

Mit der Angabe UTF-8 allein ist erst die Hälfte geklärt.

In der Praxis wirken auch diese Punkte:

  • Gibt es ein BOM oder nicht
  • Ist der Zeilenumbruch CRLF oder LF

Bei ein und demselben UTF-8 kann es zum Beispiel sein, dass

  • manche Windows-Tools nur mit BOM lesen können
  • manche Unix-seitigen Verarbeitungen bei vorhandenem BOM ein überflüssiges Zeichen in der ersten Spalte bekommen
  • manche Legacy-Tools mit reinem LF schlecht zurechtkommen
  • CRLF Shell-Skripte oder Diffs unübersichtlich macht

Es kann also durchaus passieren, dass selbst bei übereinstimmender Zeichenkodierung noch ein Unfall entsteht.

5.6 Tools ändern Dinge eigenmächtig

Noch lästiger ist, dass die eigenen Werkzeuge Dinge stillschweigend ändern.

  • Der Editor erkennt die Kodierung automatisch
  • Beim Speichern wird ein BOM hinzugefügt oder entfernt
  • Git wandelt CRLF / LF um
  • Shells und Befehle speichern mit ihrer jeweiligen Standardkodierung
  • Ein CSV-Export verwendet eine unerwartete Codepage
  • Andere PowerShell- oder Tool-Versionen haben unterschiedliche Standardwerte

Mit anderen Worten: Auch wenn die ausführende Person nichts explizit vorgegeben hat, fügt irgendeine Ebene eigenmächtig eine Annahme hinzu — das ist der Windows-Alltag in der Praxis.

Das ist die wahre Ursache von „ich habe nichts geändert, und trotzdem ist es kaputt“. Tatsächlich war es oft nicht ein Mensch, sondern der Standardwert eines Tools, der die Änderung vorgenommen hat.

6. Typische Unfallmuster

Typische Unfälle in Tabellenform:

Situation Was tatsächlich nicht übereinstimmt Typisches Symptom
Ein Legacy-Windows-Tool behandelt eine Konfigurationsdatei in UTF-8 ohne BOM als ANSI / CP932 Decodier-Annahme Nur das Japanische wird zu Mojibake
Eine CP932-CSV wird an eine UTF-8-erwartende Verarbeitung übergeben Decodier-Annahme , Decodierfehler, unverständliches Japanisch
Ein UTF-16LE-Protokoll wird an Unix-seitige Textwerkzeuge übergeben Kodierungs-Annahme NUL-Bytes mischen sich ein, wirkt binärartig
Eine LF-Quelldatei wird in einer anderen Umgebung nach CRLF konvertiert Zeilenumbruch-Annahme Riesige Zeilenend-Diffs, Skriptfehlfunktionen
Falsch gelesener Inhalt wird unverändert gespeichert Die Byte-Folge selbst wird zu etwas anderem Unwiderruflicher Datenverlust
Die Spezifikation sagt nur „Gib eine CSV aus“ Die Schnittstelle ist nicht definiert In Excel lesbar, in einem anderen Tool kaputt
Es wird nur „Vereinheitlichung auf UTF-8“ festgelegt BOM / Zeilenumbruch sind nicht definiert Nur bestimmte Tools schlagen fehl

Besonders gefährlich ist das Muster, einen Anzeigefehler zu sehen und ihn dann durch Speichern zu einem festen Unfall zu machen.

7. Regeln, die in der Praxis Unfälle reduzieren

Ab hier geht es darum, welche Betriebsregeln Unfälle reduzieren.

7.1 Die Grundlinie für neue Textdateien festlegen

Bei neuen Dateien ist es sinnvoll, zunächst UTF-8 als erste Wahl anzusetzen. Das allein genügt jedoch nicht.

Mindestens sollte man auch Folgendes festlegen:

  • UTF-8 mit BOM oder UTF-8 ohne BOM
  • Ist der Zeilenumbruch CRLF oder LF
  • Wer liest diese Datei
  • Ist Kompatibilität mit Legacy-Windows-Tools nötig
  • Lesen auch Linux / macOS / CI / Container mit

Bei plattformübergreifendem Quellcode oder Konfigurationsdateien ist zum Beispiel UTF-8 ohne BOM + LF meist die erste Wahl. Muss man sich dagegen an ältere Windows-Tools oder bestehenden Betrieb anpassen, kann UTF-8 mit BOM oder auch CP932 + CRLF weiterhin nötig sein.

Wichtig ist, sich nicht an allgemeinen Vorstellungen von „was richtig ist“ zu orientieren, sondern danach zu entscheiden, mit wem man es zu tun hat.

7.2 Bestehende Legacy-Dateien nicht eigenmächtig ändern

Ist eine bestehende Datei CP932, ist es sicherer, sie nicht im Vorbeigehen bei einer kleinen Korrektur auf UTF-8 umzustellen.

Der sichere Betrieb sieht so aus:

  • Bestehende Dateien behalten ihre ursprüngliche Kodierung / ihr BOM / ihren Zeilenumbruch
  • Die Kodierungsumstellung wird als separate Migrationsaufgabe abgetrennt
  • Erst nach Prüfung der Umstellungsziele und der nachgelagerten Verwendung erfolgt eine Sammelumstellung

Mojibake-Unfälle entstehen häufig aus dem gut gemeinten „Modernisieren wir das gleich mit“.

7.3 Zeichenkodierung und Zeilenumbruch als Teil der Schnittstelle behandeln

Bei CSV, TXT, Protokollen, Konfigurationsdateien und einfachen Protokollen ist nicht nur der Inhalt, sondern das Textformat selbst die Schnittstelle.

In der Spezifikation sollte mindestens Folgendes stehen:

  • die Zeichenkodierung
  • ob es ein BOM gibt
  • der Zeilenumbruch
  • ob es eine Kopfzeile gibt
  • die Spezifikation von Anführungszeichen / Trennzeichen
  • mit welchem Tool geprüft wurde

Die drei Buchstaben CSV allein reichen zum Beispiel nicht aus. Erst wenn man UTF-8 mit BOM, CRLF, kommagetrennt, mit Kopfzeile schreibt, driftet das Gespräch nicht mehr auseinander.

7.4 An den Lese-/Schreibgrenzen explizit sein

Auch auf der Code-Seite ist es sicherer, sich nicht auf stillschweigende Standardwerte zu verlassen.

  • Beim Lesen und Schreiben von Dateien die Zeichenkodierung explizit angeben
  • Auch bei der Textübergabe zwischen Prozessen auf die Zeichenkodierung achten
  • Bei Export-/Import-Vorgängen auch den Zeilenumbruch als Teil der Spezifikation festlegen
  • Eine beiläufige Shell-Umleitung nicht zum Produktionspfad machen

Gerade unter Windows sind „es hat gespeichert“ und „es hat mit der richtigen Byte-Folge gespeichert“ nicht dasselbe.

7.5 Auch die Regeln für Git und Editor teilen

Git ist kein Werkzeug, das Zeichenkodierungen automatisch korrigiert. Bei Zeilenumbrüchen hingegen kann eine Umwandlung stattfinden.

Deshalb ist es sicherer, pro Repository Folgendes festzulegen:

  • Soll Quellcode grundsätzlich LF verwenden
  • Wird bei rein Windows-spezifischem Text CRLF toleriert
  • Wie wird das über .gitattributes fixiert
  • Wie werden Editor-Einstellungen geteilt

Es ist wichtig, Zeichenkodierung und Zeilenumbruch getrennt zu betrachten. Auch wenn Git die Zeilenumbrüche angleicht, bleiben Kodierungsunfälle davon unberührt.

7.6 Nicht bei „es ist Mojibake“ stehen bleiben, sondern benennen, was nicht übereinstimmt

In der Praxis wirkt diese Umformulierung oft Wunder:

  • Schlechte Formulierung: „Es ist Mojibake“
  • Gute Formulierung: „Es sieht so aus, als würde eine UTF-8-ohne-BOM-Datei unter der Annahme CP932 geöffnet“
  • Schlechte Formulierung: „Die Zeilenenden sind komisch“
  • Gute Formulierung: „Eine LF-Datei wird nach CRLF konvertiert, wodurch der Diff aufgebläht wird“

Allein die Fähigkeit, benennen zu können, was nicht übereinstimmt, verändert die Geschwindigkeit der Untersuchung erheblich.

7.7 So prüfen Sie es - Fundstellen je Tool

Die bisherigen Regeln greifen erst zusammen mit den Mitteln, sie zu überprüfen. Für drei häufig genutzte Tools fassen wir zusammen, „wo man die aktuelle Zeichenkodierung sieht“ und „wo man sie ändert“.

Tool Wo man die aktuelle Zeichenkodierung sieht Wo man sie ändert
VS Code In der Statusleiste unten rechts im Fenster. Dort stehen nebeneinander eine Kodierung wie UTF-8 und die Zeilenumbruch-Anzeige CRLF / LF Klickt man auf die Kodierungsanzeige in der Statusleiste, erscheinen die Optionen zum erneuten Öffnen oder erneuten Speichern. Der Standardwert steht in den Einstellungen unter files.encoding
Editor (Notepad) Die Kodierung des Dokuments wird in der Statusleiste angezeigt Über „Datei“ → „Speichern unter“ öffnen und im Feld „Codierung“ des Dialogs auswählen
PowerShell Am zuverlässigsten sieht man die ersten Bytes der Datei direkt an (Befehl siehe unten) Der Parameter -Encoding des jeweils schreibenden Cmdlets. Der Standardwert steht in $PSDefaultParameterValues

VS Code

Der Standard von VS Code für die Zeichenkodierung ist UTF-8 (ohne BOM). Möchte man das für eine einzelne Datei ändern, klickt man auf die Anzeige in der Statusleiste und wählt, ob man die aktuell geöffnete Datei mit einer anderen Kodierung erneut öffnet oder mit einer anderen Kodierung neu speichert. Wurde nur falsch gelesen, öffnet man zunächst erneut — das entspricht der Einschätzung aus 3.2.

Um den Standardwert zu ändern, gibt man in den Einstellungen files.encoding an. Als Werte kommen utf8 (ohne BOM), utf8bom (mit BOM), utf16le, windows1252 und Ähnliches infrage. Auch eine Aufteilung nach Sprache ist möglich.

{
  "files.encoding": "utf8",
  "[powershell]": {
    "files.encoding": "utf8bom"
  }
}

Nur Skripte, die unter Windows PowerShell 5.1 laufen sollen, mit BOM zu versehen — die Unterscheidung aus 2.4 — lässt sich über diese sprachspezifische Einstellung abbilden.

Editor (Notepad)

Ab Windows 10 Build 18963 hat der Windows-Editor in der Statusleiste eine Spalte, die die Kodierung des Dokuments anzeigt, und der Standard für neue Dateien ist UTF-8 (ohne BOM). Beim Speichern öffnet man über „Datei“ → „Speichern unter“ und wählt im Feld „Codierung“ des Dialogs. In diesem Feld lässt sich auch das Vorhandensein eines BOM auswählen, sodass sich die in 7.1 festgelegte Richtlinie hier umsetzen lässt.

Bei der Meldung „Beim Öffnen im Editor war es Mojibake“ lohnt es sich, zuerst dieses Feld und die Anzeige in der Statusleiste zu prüfen.

PowerShell

Der Standard von PowerShell unterscheidet sich stark je nach Version. Ohne dieses Wissen entstehen häufig Anfragen der Art „ich habe mit PowerShell ausgegeben, aber das Tool kann es nicht lesen“.

  • PowerShell 6 und höher (die PowerShell-7-Reihe): Der Standard für sämtliche Textausgaben ist utf8NoBOM, also UTF-8 ohne BOM.
  • Windows PowerShell 5.1: Die Standardwerte sind von Cmdlet zu Cmdlet uneinheitlich.

Die wichtigsten in 5.1 in Tabellenform:

Befehl Standard beim Schreiben
Out-File, die Umleitungsoperatoren > >> UTF-16LE
Set-Content, Add-Content (wenn das Ziel leer ist oder nicht existiert) Default (aktive Codepage; in japanischen Umgebungen CP932)
Export-Csv Ascii
Start-Transcript UTF-8 mit BOM
New-Item -Type File -Value UTF-8 ohne BOM

Auch beim Lesen gibt es Standardwerte. Fehlt ein BOM, gehen Get-Content und die PowerShell-Engine beim Lesen von Skriptdateien von Default (aktive Codepage) aus, während Import-Csv und Select-String UTF-8 annehmen. Selbst bei derselben Datei ändert sich die Annahme also danach, mit welchem Cmdlet man liest.

Ob die aktuell vorliegende Datei ein BOM besitzt, lässt sich anhand der ersten Bytes feststellen.

# PowerShell 7: die ersten 3 Bytes hexadezimal anzeigen
Get-Content -Path .\sample.txt -AsByteStream -TotalCount 3 | Format-Hex

# Windows PowerShell 5.1 kennt -AsByteStream nicht, daher -Encoding Byte verwenden
Get-Content -Path .\sample.txt -Encoding Byte -TotalCount 3 | Format-Hex

Stehen am Anfang EF BB BF, ist es UTF-8 mit BOM; bei FF FE ist es UTF-16LE; sonst gibt es kein BOM. Das entspricht derselben Betrachtung wie in der Tabelle aus 2.4.

Möchte man den Standard explizit fixieren, verwendet man $PSDefaultParameterValues.

# Den Standard für alle Cmdlets mit dem Parameter Encoding auf UTF-8 setzen
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

Hier liegt eine Falle zwischen den Versionen. Dieselbe Zeichenkette utf8 bedeutet unter Windows PowerShell 5.1 UTF-8 mit BOM, ab PowerShell 6 aber UTF-8 ohne BOM. Möchte man auch das Vorhandensein des BOM fixieren, ist es sicherer, die ab PowerShell 6 verfügbaren Werte utf8BOM / utf8NoBOM explizit anzugeben.

$OutputEncoding ist zudem die Zeichenkodierung für die Übergabe an externe Programme und wirkt sich nicht auf die Kodierung aus, mit der Umleitungen oder Cmdlets in eine Datei speichern. Das wird leicht verwechselt.

8. Mojibake- und Zeilenende-Untersuchungen mit diesen 5 Fragen angehen

Kommt man bei der Untersuchung nicht weiter, ist die Rückkehr zu diesen 5 Fragen der schnellste Weg.

  1. Wie lautet die Byte-Folge dieser Datei gerade jetzt
    • UTF-8?
    • UTF-8 mit BOM?
    • CP932?
    • UTF-16LE?
  2. Wer hat sie zuerst geschrieben, unter welcher Annahme
    • Editor
    • Legacy-Anwendung
    • Excel-Export
    • Shell / Skript
    • Batch / Middleware
  3. Wer liest sie gerade, unter welcher Annahme
    • automatische Erkennung des Editors
    • Codepage der Konsole
    • Standardkodierung der Bibliothek
    • Spezifikation der importierenden Seite
  4. Wie sind BOM und Zeilenumbruch
    • BOM vorhanden / nicht vorhanden
    • CRLF / LF
  5. Wurde der falsch gelesene Inhalt bereits gespeichert
    • noch nur Anzeige?
    • bereits erneut gespeichert, sodass die ursprünglichen Bytes verloren sind?

Sind diese 5 Fragen beantwortet, zeigt sich meist die Ursache.

9. Zusammenfassung

Dass Windows-Zeichenkodierung und Zeilenumbrüche kompliziert wirken, liegt nicht daran, dass Japanisch selbst schwierig wäre. Es liegt daran, dass Byte-Folge, Zeichenkodierung, BOM, Zeilenumbruch und die Standardwerte der Tools unabhängig voneinander existieren und unter Windows zudem alte und neue Textkulturen nebeneinander bestehen.

Besonders diese 6 Punkte sind es wert, im Kopf zu behalten:

  • Mojibake ist das Ergebnis davon, dieselbe Byte-Folge mit einer anderen Zeichenkodierung zu lesen
  • Das Zeilenumbruch-Problem liegt auf einer anderen Achse als die Zeichenkodierung
  • Den Begriffen Shift_JIS, CP932, ANSI, Unicode sollte man nicht blind vertrauen
  • „Wir haben auf UTF-8 umgestellt“ allein reicht nicht — BOM und Zeilenumbruch werden ebenfalls gebraucht
  • Anzeigefehler und bereits erneut gespeicherter Datenverlust sollten getrennt betrachtet werden
  • In Spezifikationen sollte nicht Text, sondern etwas wie UTF-8 ohne BOM, LF stehen

Kurz gesagt: Beim Umgang mit Text unter Windows ist es praxistauglich, das nicht als „Diskussion über Zeichenketten“ zu betrachten, sondern als Diskussion darüber, wie man sich auf den Vertrag über die Bytes einigt.

10. Verwandte Artikel

11. Quellen

  1. Microsoft Learn, Code Page Identifiers - Win32 apps https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
  2. Microsoft Learn, about_Character_Encoding - PowerShell https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-7.6
  3. Microsoft Learn, Understanding file encoding in VS Code and PowerShell https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding?view=powershell-7.6
  4. W3C Internationalization, Character encodings: Essential concepts https://www.w3.org/International/articles/definitions-characters/
  5. Git documentation, gitattributes https://git-scm.com/docs/gitattributes
  6. Git documentation, git-config https://git-scm.com/docs/git-config
  7. Microsoft Learn, The Unicode standard - Globalization (zur Byte-Folge des BOM und dazu, dass das BOM bei UTF-8 als Signatur verwendet wird) https://learn.microsoft.com/en-us/globalization/encoding/unicode-standard
  8. Microsoft Learn, What was new in 20H1 Windows 10 Insider Preview Builds (zur UTF-8-Standardeinstellung des Editors ab Build 18963 und zur neu hinzugefügten Kodierungsanzeige in der Statusleiste) https://learn.microsoft.com/en-us/previous-versions/windows-insider/archive/new-in-20h1

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Technische Beratung und Design-Review

In Projekten, in denen die Annahmen zur Zeichenkodierung von CSVs, Protokollen und Konfigurationsdateien zwischen Windows und Linux auseinanderdriften, lässt sich das Unfallrisiko deutlich senken, wenn der I/O-Vertrag und die Betriebsregeln vorab geklärt werden.

Windows-App-Entwicklung

Bei Fachwerkzeugen für Windows sind CP932 und UTF-8 in der Praxis häufig gemischt, weshalb der Umgang mit Zeichenkodierung und Zeilenumbrüchen bereits im Design berücksichtigt werden sollte — das wirkt sich direkt auf die Wartbarkeit aus.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Warum entsteht Mojibake?
Weil dieselbe Byte-Folge mit einer anderen Zeichenkodierung gelesen wird, als mit der sie geschrieben wurde. Speichert man beispielsweise „あ“ als UTF-8, ergeben sich die Bytes E3 81 82; liest man diese aber unter der Annahme CP932, erscheint eine andere Zeichenfolge wie „縺“. Kaputt ist hier nicht das Japanische, sondern die Decodier-Annahme. Speichert man den falsch gelesenen Inhalt jedoch unverändert erneut, gehen die ursprünglichen Bytes verloren — dann wird aus dem Anzeigefehler ein Datenverlust. Deshalb ist es wichtig, die Datei vor dem Speichern mit der richtigen Kodierung neu zu öffnen.
Was ist der Unterschied zwischen CRLF und LF?
Es ist ein Unterschied bei den Bytes, die als Zeilentrenner verwendet werden. CRLF besteht aus den zwei Bytes 0D 0A und wird traditionell in Windows-Textdateien verwendet, LF besteht aus dem einen Byte 0A und ist unter Linux/macOS sowie in vielen Entwicklungswerkzeugen üblich. Wichtig ist, dass der Zeilenumbruch ein von der Zeichenkodierung getrenntes Thema ist. Auch bei derselben UTF-8-Datei kann der Zeilenumbruch CRLF oder LF sein — wenn also „wir haben auf UTF-8 umgestellt, aber es passt immer noch nicht“ auftritt, liegt es manchmal nicht an der Kodierung, sondern allein am Zeilenumbruch.
Sind Shift_JIS und CP932 dasselbe?
Im Gespräch versteht man sich damit, aber in der Praxis ist eine Unterscheidung sicherer. Wer japanischen Legacy-Text unter Windows präzise fassen möchte, sollte an CP932 beziehungsweise die Windows-eigene japanische Codepage denken. Ebenso bezeichnet „ANSI“ unter Windows meist die aktive Codepage der jeweiligen Maschine, und der Menüpunkt „Unicode“ in Editoren bedeutet mitunter UTF-16LE. In Spezifikationen und Untersuchungsnotizen drifted das Gespräch weniger, wenn man konkret schreibt, etwa „UTF-8 ohne BOM, LF“.
Was sollte man bei der Spezifikation einer Textdatei festlegen?
„Wir haben auf UTF-8 umgestellt“ allein genügt nicht — erst wenn auch das Vorhandensein eines BOM und der Zeilenumbruch festgelegt sind, wird daraus eine belastbare Betriebsregel. Bei Austauschdateien wie CSV oder Protokollen ist es sicherer, auch Kodierung, BOM-Status, Zeilenumbruch, Vorhandensein einer Kopfzeile und das Trennzeichen schriftlich festzuhalten. Bei plattformübergreifendem Quellcode oder Konfigurationsdateien ist UTF-8 ohne BOM + LF meist die erste Wahl, während bei der Anpassung an ältere Windows-Werkzeuge UTF-8 mit BOM oder auch CP932 + CRLF weiterhin nötig sein kann.

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.

Zurück zum Blog