zipfile und dateien mit umlauten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
makro
User
Beiträge: 25
Registriert: Sonntag 12. Juli 2009, 08:53

Hallo,

habe ein problem mit zipfile und wenn ich dateien die umlaute enthalten (ö,ü,ä..), so werden diese dateien in der zip-datei falsch dargestellt.

also z.b.

Code: Alles auswählen

# -*- coding: cp1252 -*-
....
_d = zipfile.ZipFile(r"C:test.zip",'w', zipfile.ZIP_DEFLATED)
_datei = u"c:\ÖÖÖ.txt"
_d.write(_datei,os.path.basename(_datei))
_d.close()
...
was muss ich da tun, dass die dateinamen identisch sind??
finki
User
Beiträge: 20
Registriert: Samstag 19. Februar 2011, 11:15

Bei mir funktioniert es problemlos.

Code: Alles auswählen

# -*- coding: cp1252 -*-

import zipfile

zip_content = zipfile.ZipFile("test.zip", "w")
zip_content.writestr("äö+.txt", "äöüß")
print zip_content.testzip()
zip_content.close()
Beim öffnen mit meinem Texteditor weiß es nicht mit welcher Zeichenkodierung es die Textdatei öffnen soll. Wenn ich (Westlich-ISO-8859-1) auswähle, werden die Zeichen so erkannt wie sie sollen. iso-8859-1 ist weitestgehend die gleiche wie cp1252 (Windows-1252). Mehr zu diesem Zeichensatz hier: Wikipedia ISO 8859-1
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

makro hat geschrieben:was muss ich da tun, dass die dateinamen identisch sind??
Keine Umlaute verwenden. Macht eh nur Scherereien. Ich zitiere aus der Python-Doku:
There is no official file name encoding for ZIP files. If you have unicode file names, you must convert them to byte strings in your desired encoding before passing them to write(). WinZip interprets all file names as encoded in CP437, also known as DOS Latin.
Eine Alternative wäre also CP437 zu verwenden. Aber lass es lieber. Umlaute haben in Dateinamen nichts zu suchen, die sind einfach nicht Cross-Platform-Kompatibel.

Ich würde dir übrigens empfehlen in Windows-Pfaden entweder den Backslash zu escapen (\\) oder raw-Strings zu verwenden (mit vorgestelltem r).
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

OS X benutzt übrigens, wenn es ein ZIP-Archiv mit einer Datei mit Umlauten erzeugt, dort das eigene interne Encoding, also UTF-8 mit canonical decomposition ab. Um das aber in das üblichere Format zu verwandeln, müsste man dies machen:

Code: Alles auswählen

unicodedata.normalize("NFC", zip_info.filename.decode("utf-8"))

Nutze ich das Kommandozeilen-Programm "zip" (Info-ZIP 3.0) landet darin der Dateiname UTF-8-kodiert, aber pre-combined, so wie es üblicher ist.

Der Standard sagt:

The ZIP format has historically supported only the original IBM PC character
encoding set, commonly referred to as IBM Code Page 437. This limits storing
file name characters to only those within the original MS-DOS range of values
and does not properly support file names in other character encodings, or
languages. To address this limitation, this specification will support the
following change.

If general purpose bit 11 is unset, the file name and comment should conform
to the original ZIP character encoding. If general purpose bit 11 is set, the
filename and comment must support The Unicode Standard, Version 4.1.0 or
greater using the character encoding form defined by the UTF-8 storage
specification.

Wurde dieses Bit gesetzt?

Code: Alles auswählen

0000000    50  4b  03  04  0a  00  00  00  00  00  f2  4c  11  3f  00  00
0000020    00  00  00  00  00  00  00  00  00  00  0c  00  1c  00  c3  a4
0000040    c3  b6  c3  bc  c3  9f  2e  74  78  74  55  54  09  00  03  38
0000060    70  4b  4e  38  70  4b  4e  75  78  0b  00  01  04  f5  01  00
0000100    00  04  00  00  00  00  50  4b  01  02  1e  03  0a  00  00  00
0000120    00  00  f2  4c  11  3f  00  00  00  00  00  00  00  00  00  00
0000140    00  00  0c  00  18  00  00  00  00  00  00  00  00  00  a4  81
0000160    00  00  00  00  c3  a4  c3  b6  c3  bc  c3  9f  2e  74  78  74
0000200    55  54  05  00  03  38  70  4b  4e  75  78  0b  00  01  04  f5
0000220    01  00  00  04  00  00  00  00  50  4b  05  06  00  00  00  00
0000240    01  00  01  00  52  00  00  00  46  00  00  00  00  00        
0000256
AFAICT nein. Wie schade. Die ersten 4 Bytes signalisieren einen locale file header. Danach kommen 2 Bytes Version (10); danach die Flags (0). Da müsste 04 00 stehen, würde ich sagen.

Info-ZIP scheint sich damit über den Standard hinwegzusetzen. Dessen Hilfe sagt:

Code: Alles auswählen

Unicode:
  If compiled with Unicode support, Zip stores UTF-8 path of entries.
  This is backward compatible.  Unicode paths allow better conversion
  of entry names between different character sets.
Man könnte wohl das 0x0008-Extra Field hinzufügen, und darin signalisieren, welches Encoding ein Name (und der Kommentar) haben, doch das ist bei mir ja nicht der Fall.

Was sagt uns das alles: Wenn man selbst eine ZIP-Datei erzeugt, sollte man Bit 11 setzen und den Namen UTF-8-kodieren.

Code: Alles auswählen

z = zipfile.ZipFile("test.zip", "w")
zi = zipfile.ZipInfo(u"äöü".encode("utf-8"))
zi.flag_bits = 1024
z.writestr(zi, "...")
z.close()
Stefan
Antworten