Thread unzip und Sonderzeichen in gepackten Datei-/Verzeichnisnamen
(14 answers)
Opened by frankes at 2009-04-29 17:51
So mal einen ersten Lösungsansatz.
Nach Recherchen im Internet weiß ich jetzt, dass das Problem im Zip-Archiv Dateiformat liegt. Während Windows Systeme anscheinend ziemlich sicher cp850 als Zeichensatz für die Dateinamen im Zip-Archiv verwendet, variiert dieser unter *nixe und anderen Systemen. Das Zip-Archiv speichert bisher nicht den verwendeten Zeichensatz für Dateinamen im Archiv. Das Problem ist bekannt und in zukünftigen zip Versionen (6.0?) soll dann der verwendete Zeichensatz mit gespeichert werden. Bis die Tage und sich das bei allen Zip Packern durchgesetzt hat, muss man halt herumspielen. Zu meiner Freude ist das Archive::Zip Modul pure Perl, so dass man es einfach durch kopieren auch auf Servern verwenden kann, wo es nicht installiert ist. Man sollte lediglich überprüfen, ob die von Archive::Zip benötigten Module installiert sind (vgl. dazu die Dokumentation von Archive::Zip). Archive::Zip bietet neben dem Packen und Entpacken eine bequeme Möglichkeit Kopfdaten zum Zip-Archiv auszulesen, als auch einzelne Files aus dem Archiv unter einem anderen Namen zu entpacken. Mittels "fileAttributeFormat()" kann man auch grob das vom Packer verwendete Dateiformat/System herausfinden. zB. MSDOS, FAT = 0; UNIX = 3; CMS = 4; OS2_HPFS = 6; MACINTOSH = 7; WINDOWS_NTFS = 11; VFAT = 14; (Eine vollständige Liste findet sich im Quellcode von Archive::Zip) Zum 1. Versuch Es würde sich nun anbieten, archivierte File-Namen die unter einem Windows/MS System gepackt wurden sofort mittels cp850 zu decodieren. Leider musste ich die Erfahrung machen, dass der KDE4 Packer Ark gleichfalls Quote angibt, aber die File-Namen im Archiv unter dem Systemzeichensatz (hier war es UTF8) abspeichert. Bleiben weitere Möglichkeiten: 1. Vor dem entpacken nicht konforme Zeichen umwandeln. 2. Versuchen, den Zeichensatz der File-Namen herauszufinden. 3. ... (vielleicht fällt euch was ein) Trotz der Problematik einen verwendeten Zeichensatz herauszufinden probiere ich es hier zunächst über die zweite Möglichkeit. Das Script entpack ein gegebenes Zip Archiv ins gleiche Verzeichnis. Beim Aufruf des Script einfach den entsprechenden Verzeichnisnamen anhängen. Quote Das Script versucht mittels Encode::Guess festzustellen, ob ein ascii oder cp850 Zeichensatz verwendet wurde. UTF8 wird leider nicht sicher erkannt. Getestet wurde das Script bisher unter Linux (UTF8) mit Archiven von XP, Vista (eigene Systempacker, 7zip, WinAce) und dem oben genannten Linux (UTF8). Wie sich das script mit einem anderen Systemzeichensatz wie UTF8 klar kommt, wird sich noch herausstellen müssen. Mich würde es nun natürlich interessieren, wie diese script mit Archiven mit anderen Zeichensätzen/ System klar kommt. Und natürlich bin ich an Verbesserungsvorschlägen interessiert. Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #!/usr/bin/perl -w ########### zip.pl ################ # Testing for modul Active::zip # Unpack given ZIP files in the same directory use lib './'; use strict; use Carp; use Encode; use Encode::Guess; use Archive::Zip qw( :ERROR_CODES :CONSTANTS ); use utf8; use open ':utf8'; binmode STDOUT,':utf8'; my $zip = Archive::Zip->new(); my @encodings = qw(ascii cp850); my $m = ''; my $n = ''; my $charset = ''; die 'read error: ',$ARGV[0] unless $zip->read( $ARGV[0] ) == AZ_OK; foreach $m ($zip->members()) { print "member filename: ",$m->fileName(),"\n"; print "fileAttributeFormat: ", $m->fileAttributeFormat(),"\n"; $n = $m->fileName(); print "Try to guess encoding\n"; $charset = guess_encoding($n, @encodings); #no charset found unless (ref $charset) { print "No charset found: $charset\n"; print "Using member filename like it is: $n\n"; $zip->extractMember($m); next; } #charset found $charset = $charset->name; print "Guessed charset: ",$charset,"\n"; print "Archive given member filename is $n.\n"; $n = decode($charset,$n); $m->extractToFileNamed($n) ; print "Decoded to $n\n"; print "----------------\n"; } print 'done.'; |