Python, файловая система UTF-8, файлы iso-8859-1

У меня есть приложение, написанное на Python 2.7, которое считывает пользовательский файл с жесткого диска с помощью os.walk.

Для приложения требуется системная локаль UTF-8 (мы проверяем переменные env перед его запуском), потому что мы обрабатываем файлы с символами Unicode (например, аудиофайлы с именем исполнителя в нем), и мы хотим убедиться, что мы можем сохранить эти файлы с помощью правильное имя файла в файловой системе.

Некоторые из наших пользователей имеют локали UTF-8 (поэтому UTF-8 fs), но каким-то образом умудряются хранить файлы ISO-8859-1 на своем диске. Это вызывает проблемы, когда наш код пытается использовать os.walk() для этих каталогов, поскольку Python выдает исключение при попытке декодировать эту последовательность байтов ISO-8859-1 с использованием UTF-8.

Итак, мой вопрос: как мне заставить python игнорировать этот файл и переходить к следующему вместо прерывания всего os.walk(). Должен ли я просто свернуть свою собственную функцию os.walk()?

Редактировать: до сих пор мы говорили нашим пользователям использовать команду convmv linux для исправления своих имен файлов, однако многие пользователи используют различные типы кодировок (8859-1, 8859-2 и т. д.), и использование convmv требует, чтобы пользователь чтобы сделать обоснованное предположение о том, какие файлы имеют какую кодировку, прежде чем запускать convmv для каждого из них в отдельности.


person Martin Konecny    schedule 27.07.2012    source источник
comment
Существует огромная разница между кодировкой имени файла и терминальной кодировкой. Вы никогда не можете предположить, что они коррелируют.   -  person Martijn Pieters    schedule 27.07.2012
comment
@Martijn Pieters: мы используем переменную env LANG.   -  person Martin Konecny    schedule 27.07.2012
comment
Не могли бы вы использовать аргумент onerror для walk()? Какое исключение выбрасывается?   -  person Silas Ray    schedule 27.07.2012
comment
@ sr2222: он выдаст UnicodeDecodeError.   -  person Sven Marnach    schedule 27.07.2012
comment
@MartinKonecny: переключение переменной env LANG не меняет кодировку, используемую в файловой системе; os.listdir() работает с сохраненными в системе именами файлов, которые не перекодируются в соответствии с текущими настройками LANG.   -  person Martijn Pieters    schedule 27.07.2012
comment
@MartijnPieters, согласен, но чтение UTF-8 из sys.getfilesystemencoding волшебным образом не делает файлы закодированными в UTF-8. Но ваш метод определенно более правильный, чем мой :)   -  person Martin Konecny    schedule 27.07.2012


Ответы (2)


Прочтите имена файлов в формате Unicode, часть руководства Python Unicode. Самое главное, кодировки файловой системы не обязательно совпадают с текущими настройками LANG в терминале.

В частности, os.walk построен на os.listdir и, таким образом, будет переключаться между юникодом и 8-битными байтами в зависимости от того, дадите ли вы ему путь юникода.

Вместо этого передайте ему 8-битный путь, и ваш код будет работать правильно, а затем при необходимости выполните декодирование из UTF-8 или ISO 8859-1.

person Martijn Pieters    schedule 27.07.2012
comment
Это путь. Использование байтовых строк (введите bytes или str в Python 2.x, введите bytes в 3.x) также сделает настройку локали неактуальной. Обратите внимание, что в Python 3.2 вся проблема исчезла, поскольку имена файлов будут декодироваться с помощью errors="surrogateescape", что никогда не дает сбоев. - person Sven Marnach; 27.07.2012
comment
Текущая кодировка файловой системы определяется переменной окружения LC_CTYPE или LANG, если первая не установлена. Его можно запросить с помощью функции Python sys.getfilesystemencoding(). - person Sven Marnach; 27.07.2012
comment
Затем декодируйте из UTF-8 или ISO 8859-1, как мне это сделать? Попробуйте сначала декодировать из UTF-8, а если исключение, попробуйте ISO-8859-1? - person Martin Konecny; 27.07.2012
comment
Декодировать из sys.getfilesystemencoding(), возможно, с помощью errors=replace или путем перехвата ошибок UnicodeDecode и игнорирования соответствующего имени файла. - person Martijn Pieters; 27.07.2012

Используйте обнаружение кодировки символов, модули charde для python хорошо работают для определения фактической кодировки с некоторой уверенностью. "при необходимости" -- вы либо знаете кодировку, либо вам приходится догадываться о ней. Если с charde вы ошиблись, по крайней мере, вы попытались.

person Marc U.    schedule 06.08.2012