Layer 8Ehrlicher Tech-Support

ZIP-Archiv: Umlaute im Dateinamen kommen falsch an

Nach dem Entpacken steht Buchstabensalat im Dateinamen. Das ZIP-Format schreibt keine feste Kodierung für Namen vor. So rechnest du sie zurück.

Aufwand:
ca. 20 Min.
Voraussetzung:
Python 3, Eine Kommandozeile, Eine Kopie des Archivs, an der man gefahrlos üben kann
Gilt für:
ZIP-Archive aus fremder Quelle, Austausch zwischen Windows, macOS und Linux, Python 3.11 und neuer für den Parameter metadata_encoding

Das Symptom

Der Kollege schickt ein Archiv, du packst es aus, und im Ordner liegen Dateien mit Namen wie Bericht_Grⁿn.txt, Prⁿfung.pdf oder Gr÷▀e_Angebot.docx. Der Inhalt der Dateien ist einwandfrei – nur die Namen sehen aus, als hätte jemand beim Tippen die Tastatur gewechselt. Auf dem Rechner des Absenders war alles in Ordnung, und er versteht nicht, wovon du redest.

Die „Layer 8“-Wahrheit

Das ZIP-Format stammt aus den späten Achtzigern und schleppt seither einen Konstruktionsfehler mit sich herum: Es speichert die Dateinamen als rohe Bytes und schrieb lange nicht vor, nach welcher Tabelle diese Bytes in Zeichen gehören. Empfohlen wurde CP437, die Kodierung des ersten IBM-PC; später kam UTF-8 dazu, angezeigt durch ein einzelnes Bit im Kopf jedes Eintrags. Dazwischen liegen Jahrzehnte, in denen unzählige Packprogramme einfach die Kodierung ihres Betriebssystems verwendet haben, ohne das Bit zu setzen – auf einem deutschen Windows also cp1252. Für dieses Archiv gilt: Die Bytes sind vollständig und korrekt, aber es steht nirgends, was sie bedeuten sollen. Das entpackende Programm nimmt die Voreinstellung, liest ein ü als ⁿ, und schon steht der Unsinn auf der Platte.

Und dort ist er dann echt. Das ist der Unterschied zu den kaputten Umlauten in einer Tabelle: Ein falsch angezeigter Inhalt ist ein Anzeigeproblem und verschwindet, sobald man richtig liest. Ein falsch gelesener Dateiname wird beim Entpacken zu einem tatsächlichen Namen im Dateisystem. Die gute Nachricht ist, dass der Vorgang umkehrbar ist, solange man weiß, welche Tabelle beim Lesen benutzt wurde: Man kodiert den Unsinn mit derselben Tabelle zurück in Bytes und liest ihn mit der richtigen. Was man dafür braucht, ist keine Spezialsoftware, sondern eine Zeile und die Bereitschaft, die richtige Kodierung zu erraten – denn raten muss man, das Archiv sagt es nicht. Genau deshalb ist ein Dateiname ohne Umlaute im Austausch mit Fremden bis heute die einzige Zusage, die man geben kann.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Nachsehen, was im Archiv wirklich steht

    Vor jeder Reparatur wird geprüft, ob das Kennzeichen für UTF-8 gesetzt ist. Das Bit hat den Wert 0x800 in den Kennzeichenbits jedes Eintrags. Kommt hier False heraus und sehen die Namen falsch aus, liegt der Fall vor, um den es hier geht:

    python3 -c "
    import zipfile
    with zipfile.ZipFile('archiv.zip') as z:
        for i in z.infolist():
            print('UTF-8-Flag:', bool(i.flag_bits & 0x800), '|', i.filename)
    "
    
  2. 2.

    Das Archiv mit der richtigen Kodierung lesen

    Ist das Kennzeichen nicht gesetzt, kann man dem Lesevorgang die tatsächliche Kodierung vorgeben. Bei Archiven aus dem deutschen Windows ist das meist cp1252, bei älteren DOS-Werkzeugen cp850. Der Parameter gilt für das ganze Archiv und ausschließlich beim Lesen – beim Schreiben lehnt Python ihn ausdrücklich ab:

    python3 -c "
    import zipfile
    with zipfile.ZipFile('archiv.zip', metadata_encoding='cp1252') as z:
        print(z.namelist())
        z.extractall('entpackt')
    "
    
  3. 3.

    Einen einzelnen bereits kaputten Namen zurückrechnen

    Wurde schon entpackt und die Datei heißt bereits falsch, ist nichts verloren: Der falsche Name entstand, indem die ursprünglichen Bytes nach cp437 gelesen wurden – das ist die Voreinstellung dieses Moduls. Man dreht den Vorgang um, indem man den Namen wieder nach cp437 kodiert und dann mit der richtigen Kodierung liest. Aus `Bericht_Grⁿn.txt` wird so wieder `Bericht_Grün.txt`. Hat ein anderes Werkzeug entpackt, ist die erste Kodierung entsprechend dessen Voreinstellung zu ersetzen:

    python3 -c "print('Bericht_Grⁿn.txt'.encode('cp437').decode('cp1252'))"
    
  4. 4.

    Die Umbenennung im Ordner durchziehen

    Dasselbe Rezept für alle Dateien eines Ordners. Der Lauf benennt nur um, was sich tatsächlich ändert, und lässt alles andere in Ruhe. Vorher eine Kopie des Ordners anlegen – bei Umbenennungen im Stapel gibt es kein Zurück:

    python3 -c "
    import os
    for alt in os.listdir('entpackt'):
        try:
            neu = alt.encode('cp437').decode('cp1252')
        except (UnicodeEncodeError, UnicodeDecodeError):
            continue
        if neu != alt:
            os.rename(os.path.join('entpackt', alt), os.path.join('entpackt', neu))
            print(alt, '->', neu)
    "
    
  5. 5.

    Beim Packen die richtige Seite wählen

    Wer selbst packt, sollte sein Werkzeug zwingen, das UTF-8-Kennzeichen zu setzen. Python tut das von allein: Enthalten die Namen Zeichen außerhalb von ASCII, wird laut Dokumentation automatisch UTF-8 verwendet, und andere Kodierungen als ASCII oder UTF-8 sind gar nicht möglich. Zur Kontrolle des Ergebnisses noch einmal Schritt eins laufen lassen:

    python3 -c "
    import zipfile
    with zipfile.ZipFile('neu.zip', 'w') as z:
        z.write('Bericht_Grün.txt')
    "
    
  6. 6.

    Den Streit vermeiden, statt ihn zu gewinnen

    Für Archive, die an Unbekannte gehen – Kunden, Behörden, Auftragnehmer mit unbekanntem Betriebssystem – ist der sicherste Dateiname immer noch der, der nur aus Buchstaben ohne Umlaute, Ziffern, Bindestrich und Unterstrich besteht. Das ist keine Kapitulation, sondern die Erkenntnis, dass ein Format ohne verbindliche Kodierungsangabe keine Zusage über Namen machen kann.

Häufige Fragen (FAQ)

?Warum weiß das Archiv nicht, wie seine eigenen Dateinamen kodiert sind?

Weil das Format es lange nicht vorgeschrieben hat. Die Python-Dokumentation zum Archivmodul sagt es unmissverständlich: Der ZIP-Standard hat historisch keine Kodierung für die Metadaten festgelegt, sondern lediglich CP437 – die ursprüngliche Kodierung des IBM-PC – für die Austauschbarkeit dringend empfohlen. Neuere Fassungen erlauben zusätzlich UTF-8, und zwar nur UTF-8. Ein Archiv aus dem Jahr 2009, gepackt mit einem deutschen Windows-Werkzeug, kann also Namen enthalten, deren Bytes zu keiner der beiden Empfehlungen gehören – und niemand hat vermerkt, welche gemeint war.

?Woran erkenne ich, ob die Namen als UTF-8 gemeint sind?

An einem einzelnen Bit im Kopf des Archiveintrags. Laut Dokumentation kann nach dem ZIP-Standard für die Kodierung der Metadaten über ein Kennzeichen im Archivkopf entweder eine IBM-Codepage – das ist die Voreinstellung – oder UTF-8 angegeben werden, und dieses Kennzeichen hat Vorrang vor allem, was man dem Leseprogramm sonst mitgibt. Ist das Bit gesetzt, sind die Namen UTF-8 und alles ist gut. Ist es nicht gesetzt, rät das entpackende Programm – und rät bei deutschen Umlauten regelmäßig falsch.

?Ist das dasselbe wie die kaputten Umlaute beim CSV-Import?

Verwandt, aber eine Ebene tiefer. Beim CSV-Import geht es um den Inhalt der Datei, hier um ihren Namen. Das macht den Schaden hartnäckiger: Der Inhalt bleibt beim Entpacken unangetastet, aber der falsch gelesene Name wird beim Anlegen der Datei auf die Platte geschrieben und ist damit echt. Anschließend hilft kein Neustart und keine andere Anzeigeeinstellung mehr – die Datei heißt jetzt wirklich so. Repariert wird deshalb nicht die Ansicht, sondern der Name.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

  1. [1]

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Verwandte Fehler