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

时间:2009-11-27 06:15:07

标签: python unicode encoding filenames 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, '.')

其输出:

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

提取后两个文件都无法访问,因为文件名中包含无效的编码字符。问题是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  

我尝试在我的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命令?

3 个答案:

答案 0 :(得分: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 file format specification,上面写着

  

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

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

答案 1 :(得分:7)

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

答案 2 :(得分:0)

我在使用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,请尝试并确保正确生成和设置区域设置。