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.
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.
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.
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:
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.
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.
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.