4

我使用 python 的 zipfile 模块来提取 .zip 存档(让我们以http://img.dafont.com/dl/?f=akvaleir上的这个文件为例。)

f = zipfile.ZipFile('akvaleir.zip', 'r')
for fileinfo in f.infolist():
    print fileinfo.filename
    f.extract(fileinfo, '.')

它的输出:

Akval�ir_Normal_v2007.ttf
Akval�ir, La police - The Font - Fr - En.pdf

这两个文件在提取后都无法访问,因为它们的文件名中有无效的编码字符。问题是 zipfile 模块没有指定输出文件名的选项。

但是,“unzip akvaleir.zip”很好地转义了文件名:

root@host:~# unzip akvaleir.zip 
Archive:  akvaleir.zip
  inflating: AkvalВir_Normal_v2007.ttf  
  inflating: AkvalВir, La police - The Font - Fr - En.pdf  

我尝试在我的 python 程序中捕获“unzip -l akvaleir.zip”的输出,这两个文件名是:

Akval\xd0\x92ir_Normal_v2007.ttf
Akval\xd0\x92ir, La police - The Font - Fr - En.pdf

如何在不捕获“unzip -l akvaleir.zip”的输出的情况下获得正确的文件名,就像 unzip 命令所做的那样?

4

3 回答 3

8

花了一些时间,但我想我找到了答案。

我认为这个词应该是 Akvaléir。我找到了一个关于这个的页面描述,用法语。当我使用您的代码片段时,我有一个字符串

>>> fileinfo.filename
'Akval\x82ir, La police - The Font - Fr - En.pdf'
>>> 

这不适用于 UTF8、Latin-1、CP-1251 或 CP-1252 编码。然后我发现 CP863 可能是加拿大编码,所以这可能来自加拿大法语区。

>>> print unicode(fileinfo.filename, "cp863").encode("utf8")
Akvaléir, La police - The Font - Fr - En.pdf
>>> 

但是,然后我阅读了Zip 文件格式规范,上面写着

ZIP 格式在历史上只支持原始的 IBM PC 字符编码集,通常称为 IBM Code Page 437。

...

如果设置了通用位 11,则文件名和注释必须支持 Unicode 标准,版本 4.1.0 或更高版本,使用 UTF-8 存储规范定义的字符编码形式。

测试它给了我与加拿大代码页相同的答案

>>> print unicode(fileinfo.filename, "cp437").encode("utf8")
Akvaléir, La police - The Font - Fr - En.pdf
>>>

我没有 Unicode 编码的 zip 文件,也不会创建一个来找出答案,所以我假设所有的 zip 文件都具有 cp437 编码。

import shutil
import zipfile

f = zipfile.ZipFile('akvaleir.zip', 'r')
for fileinfo in f.infolist():
    filename = unicode(fileinfo.filename, "cp437")
    outputfile = open(filename, "wb")
    shutil.copyfileobj(f.open(fileinfo.filename), outputfile)

在我的 Mac 上

 109936 Nov 27 01:46 Akvale??ir_Normal_v2007.ttf
  25244 Nov 27 01:46 Akvale??ir, La police - The Font - Fr - En.pdf

哪个选项卡完成

ls Akvale\314\201ir

并在我的文件浏览器中显示一个漂亮的“é”。

于 2009-11-27T09:49:45.440 回答
7

代替extract方法,使用open方法并将生成的伪文件以您希望的任何名称保存到磁盘,例如使用shutil.copyfileobj.

于 2009-11-27T06:33:02.030 回答
2

我在使用 Docker 运行我的应用程序时遇到了类似的问题。将此行添加到 Dockerfile 中,为我修复了所有问题:

RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

所以,我想如果你不使用 Docker,试试看并确保正确生成和设置语言环境。

于 2017-01-30T02:02:35.603 回答