Как обрабатывать некодируемые имена файлов в Python? - PullRequest
9 голосов
/ 05 августа 2010

Я бы очень хотел, чтобы мое приложение на Python работало исключительно со строками Unicode. В последнее время у меня все шло хорошо, но я столкнулся с проблемой обработки путей. POSIX API для файловых систем не является Unicode, поэтому файлы могут иметь (и на самом деле довольно распространенные) имена с «не декодируемыми» именами: имена файлов, которые не закодированы в указанной кодировке файловой системы.

В Python это проявляется как смесь unicode и str объектов, возвращаемых из os.listdir().

>>> os.listdir(u'/path/to/foo')
[u'bar', 'b\xe1z']

В этом примере символ '\xe1' закодирован в Latin-1 или в некотором роде, даже когда (гипотетическая) файловая система сообщает sys.getfilesystemencoding() == 'UTF-8' (в UTF-8 этот символ будет двумя байтами '\xc3\xa1'). По этой причине вы получите UnicodeError s повсюду, если попытаетесь использовать, например, os.path.join() с путями Unicode, потому что имя файла не может быть декодировано.

Python Unicode HOWTO предлагает этот совет о путевых именах Unicode:

Обратите внимание, что в большинстве случаев следует использовать API-интерфейсы Unicode. API байтов следует использовать только в системах, где могут присутствовать некодируемые имена файлов, то есть в системах Unix.

Поскольку я в основном беспокоюсь о системах Unix, означает ли это, что я должен реструктурировать свою программу, чтобы иметь дело только с байтовыми строками для путей? (Если так, как я могу поддерживать совместимость с Windows?) Или есть другие, более эффективные способы работы с некодируемыми именами файлов? Являются ли они достаточно редкими «в дикой природе», чтобы я просто попросил пользователей переименовать их проклятые файлы?

(Если лучше иметь дело только с внутренними строками, у меня возник вопрос: как хранить строки байтов в SQLite для одного столбца, сохраняя остальные данные в виде дружественных строк Юникода?)

Ответы [ 2 ]

5 голосов
/ 06 августа 2010

У Python есть решение этой проблемы, если вы готовы перейти на Python 3.1 или более позднюю версию:

PEP 383 - Не декодируемые байты в интерфейсах системных символов .

2 голосов
/ 05 августа 2010

Если вам нужно хранить строки байтов в БД, предназначенной для UNICODE, то, вероятно, проще записать строки байтов, закодированные в шестнадцатеричном формате. Таким образом, шестнадцатеричная строка безопасна для хранения в виде строки Юникода в БД.

Что касается вопроса о путевых именах в UNIX, я понимаю, что для имен файлов не применяется особая кодировка, поэтому вполне возможно иметь Latin-1, KOI-8-R, CP1252 и другие в различных файлах. Это означает, что каждый компонент в пути может иметь отдельную кодировку.

Я хотел бы попытаться угадать кодировку имен файлов, используя что-то вроде chardet module . Конечно, нет никаких гарантий, поэтому вам все равно придется обрабатывать исключения, но у вас будет меньше некодируемых имен. Некоторое программное обеспечение заменяет не декодируемые символы на? который необратим. Я бы предпочел, чтобы они были заменены на \ xdd или \ xdddd, потому что при необходимости их можно отменить вручную. В некоторых приложениях может оказаться возможным представить строку пользователю, чтобы он мог вводить символы Юникода для замены не кодируемых.

Если вы пойдете по этому маршруту, вы можете в конечном итоге расширить chardet для выполнения этой работы. Было бы неплохо дополнить его утилитой, которая сканирует файловую систему, находя не кодируемые имена, и создает список, который можно отредактировать, а затем отправить обратно, чтобы исправить все имена с эквивалентами Юникода.

...