使用Python提取文件名中包含无效字符的文件

jac*_*ack 4 python unicode filenames encoding zipfile

我使用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, '.')
Run Code Online (Sandbox Code Playgroud)

它的输出:

Akval?ir_Normal_v2007.ttf
Akval?ir, La police - The Font - Fr - En.pdf
Run Code Online (Sandbox Code Playgroud)

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

但是,"解压缩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  
Run Code Online (Sandbox Code Playgroud)

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

Akval\xd0\x92ir_Normal_v2007.ttf
Akval\xd0\x92ir, La police - The Font - Fr - En.pdf
Run Code Online (Sandbox Code Playgroud)

如何在不捕获"unzip -l akvaleir.zip"输出的情况下获取正确的文件名,如unzip命令?

And*_*lke 8

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

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

>>> fileinfo.filename
'Akval\x82ir, La police - The Font - Fr - En.pdf'
>>> 
Run Code Online (Sandbox Code Playgroud)

这在UTF8,Latin-1,CP-1251或CP-1252编码中不起作用.然后我发现CP863可能是加拿大编码,所以也许这来自法国加拿大.

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

然而,我再读取Zip文件格式规范其说

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

...

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

测试结果给出了与加拿大代码页相同的答案

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

我没有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)
Run Code Online (Sandbox Code Playgroud)

在我的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
Run Code Online (Sandbox Code Playgroud)

哪个标签完成

ls Akvale\314\201ir
Run Code Online (Sandbox Code Playgroud)

并在我的文件浏览器中显示一个漂亮的'é'.

  • 是的,您必须事先知道源编码.ZIP格式绝对不包含任何信息,您可以从中找出正在使用的编码文件名.虽然Mac和大多数现代Linuxen明智地将UTF-8用于其文件系统和ZIP内部,但Windows机器使用系统代码页,该代码页依赖于语言环境,而不是UTF-8.这真是令人头疼. (2认同)

Ale*_*lli 7

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

  • +1不要使用`extract`或`extractall`,除非您已经彻底检查了所有文件名,因为它可以在文件系统的任何地方喷出文件. (2认同)