虽然zip诞生之初只支持cp437,但对UTF-8的支持早已加入zip格式的标准之中,原本这样就该天下太平了。但这个世界爱自作主张和固守陈规的软件太多了,尤其是悲剧只发生在Linux用户的头上的时候(当然Win用户从JP下回的zip乱码的可能性也有,不过Win下JP的东西什么都是乱码,所以无所谓了)。于是常常会解压一个zip得到一大堆乱码的文件,如果运气好的话,可以convmv解决;但是遇到解压完的文件名里有一堆的“(invalid encoding)”,那convmv也回天乏术;更不幸的是直接解压不能,说什么

checkdir error:  cannot create ?R?X?v???-?^?Wblabla
                 Invalid or incomplete multibyte or wide character
                 unable to process ?R?X?v???-?^?Wbalbla/gao.

早先的unzip,比如UnZip 5.52,有个在usage, help和manpage等各种文档中都没提到的神秘参数-O可以指定文件名的编码,从而解决GBK/BIG5/shift_JIS等编码的乱码问题。比如:

unzip -O CP936 怎样打飞机.zip

可是到了新版本的unzip,比如UnZip 6.00,这个-O参数便名花有主了,而原来的-O功能似乎神隐了。用力搞了很久没搞定,最后求助perl。利用Archive::Zip和Encode,写了个简短的脚本,这个问题瞬间解决。

#!/usr/bin/perl

use Archive::Zip;
use Encode qw(decode encode);

sub usage {
	print <<USAGE;
USAGE: unzip.pl ZIPFILE [FROMCODE=utf-8 [TOCODE=utf-8]]
USAGE
	exit;
}

usage unless -e $ARGV[0];
$zip = Archive::Zip->new($ARGV[0]);
$from = $ARGV[1] || 'utf-8';
$to = $ARGV[2] || 'utf-8';

for ($zip->memberNames()) {
	$member = $zip->memberNamed($_);
	$_ = encode($to, decode($from, $_));
	$zip->extractMember($member, $_);
}

现在只要

perl unzip.pl 怎样打飞机.zip GBK

就能顺利解压了。至于开头提到的原因不明的乱码造成的解压不能的情况,可以直接将$_ = encode($to, decode($from, $_))这句修改文件名的代码替换为s#.*?/#gao/#等能解决问题的代码。

5 Responses to “perl脚本解决zip中文文件名乱码”
  1. Name says:

    神脚本,感谢

  2. quark says:

    原先的 -O 是一个补丁的效果,新版本大概补不上了 -.-
    抱怨贴:https://bugs.launchpad.net/ubuntu/+source/unzip/+bug/203609

  3. quark says:

    ym! 原来 -O 是隐藏参数啊,前些时候也发现不认 -O 参数的问题。一直以为新版本的开发者太 geek 或者是自认为可以完美解决这个问题就把它弄掉了 -.-

  4.  
Leave a Reply