Толик Востряков
Русские имена файлов в zip-архиве и Python
Мне всегда доставляет удовольствие узнать что-то новое в программировании или технологиях. И недавно мне повезло. Аж целых две новые штуки за раз! В этом посте расскажу о первой, а в следующем о второй.
Итак задача стояла: загрузить на сервер zip-архив картинок товаров, пройтись на сервере по всем именам файлов в архиве, производя над каждым файлом определенные действия. Следуют сказать, что названия файлов были чрезвычайно важны, так как название файла - это код товара. По этому коду в базе находился нужный товар и к нему крепился распакованный файл из архива. Все естественно работало на ура, пока названия были англоязычные, но как только коды товаров, а соответственно и названия файлов стали попадаться с русскими буквами все поломалось. И что же обнаружилось?
- Кодировка названий файлов в zip-архиве созданным под виндой оказалась не Windows-1251 и даже не KOI8-R, а CP866 (кодировка времен DOS). Под маком имена файлов кодируются в UTF-8.
- Работа с русскими названиями файлов в Питоне зависит от ниже лежащей операционной системы. Немного света на этот вопрос пролил раздел Unicode filenames. Совет из этого раздела "When opening a file for reading or writing, you can usually just provide the Unicode string as the filename, and it will be automatically converted to the right encoding for you..." оказался не всегда верным, так как на нашем виртуальном сервере под FreeBSD оказалась была задана кодировка ASCII для имен файлов и изменить ее без обращения в тех. поддержку не представлялось возможным (узнать кодировку можно с помощью команды sys.getfilesystemencoding() ). А без ее изменения попытка открыть файл с названием в формате unicode все падало. Оказалось универсальным методом является преобразовать строку в обычную 8-битную в формате UTF-8 и уже полученную строку подсунуть в функцию открытия файла
open(filename, 'w').
Итак, код распаковывающий по-файлово zip-архив с русскими названиями файлов в нем, работающий как на архивах созданных под Windows, так и под Mac (сам код работает успешно под Mac и Unix) будет выглядеть так:
from zipfile import ZipFile
import os
# путь для распаковки файлов
path = os.path.join(settings.PROJECT_DIR, 'media/upload/products')
f = ZipFile(filename, 'r')
for name in f.namelist():
try:
unicode_name = name.decode('UTF-8').encode('UTF-8')
except:
unicode_name = name.decode('cp866').encode('UTF-8')
# some analyzing of unicode_name and execute some actions
# ...
file_name = os.path.join(path, unicode_name)
f2 = open(file_name, 'w')
#f.extract(name, path) # works only for python 2.6+
f2.write(f.read(name))
f2.close()
f.close()
- 27 Авг 15:08




