Извлечь файлы с недопустимыми символами в имени файла с помощью Python - PullRequest
3 голосов
/ 27 ноября 2009

Я использую модуль zipfile в python для извлечения архива .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  

Я попытался записать вывод "unzip -l akvaleir.zip" в моей программе на python, и эти два имени файла:

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

Как я могу получить правильное имя файла, например, что делает команда unzip без захвата вывода "unzip -l akvaleir.zip"?

Ответы [ 3 ]

8 голосов
/ 27 ноября 2009

Прошло некоторое время, но я думаю, что нашел ответ.

Я предположил, что это слово должно быть Аквалир. Я нашел описание страницы на французском языке. Когда я использовал ваш фрагмент кода, у меня была строка типа

>>> 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 437.

...

Если установлен бит 11 общего назначения, имя файла и комментарий должны поддерживать Стандарт Юникод, версия 4.1.0 или больше с использованием кодировки символов форма определяется хранилищем UTF-8 спецификация.

Тестирование дает мне тот же ответ, что и канадская кодовая страница

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

У меня нет zip-файла в кодировке Unicode, и я не собираюсь его создавать, поэтому я просто предположу, что все 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

и появляется с хорошим 'é' в моем файловом браузере.

7 голосов
/ 27 ноября 2009

Вместо метода extract используйте метод open и сохраните полученный псевдофайл на диск под любым именем, например, с shutil.copyfileobj.

0 голосов
/ 30 января 2017

Я столкнулся с подобной проблемой при запуске приложения с помощью 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, попробуйте и убедитесь, что локали правильно сгенерированы и установлены.

...