2014-12-08 2 views
6

Этот код:Python 3: os.walk() пути к файлам UnicodeEncodeError: кодек 'UTF-8' не может кодировать: Суррогаты не допускается

for root, dirs, files in os.walk('.'): 
    print(root) 

дает мне эту ошибку:

UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 27: surrogates not allowed 

Как мне пройти через дерево файлов, не получая токсичных строк?

+0

, выпуск питона 3? –

+0

Python 3.4.0 (по умолчанию, 11 апреля 2014, 13:05:11) на Ubuntu 14.04. У меня есть «LANG = en_US.UTF-8' –

+2

« print (root.encode («utf-8», «surrogateescape»)) 'имеет какой-то эффект? –

ответ

11

В Linux имена файлов «всего лишь пучок байтов» и не обязательно кодируются в конкретной кодировке. Python 3 пытается превратить все в строки Unicode. При этом разработчики разработали схему для перевода байтовых строк в строки Unicode и обратно без потерь и без знания исходной кодировки. Они использовали частичные суррогаты для кодирования «плохих» байтов, но обычный кодер UTF8 не может обрабатывать их при печати на терминал.

Например, вот не-UTF8 байт строки:

>>> b'C\xc3N'.decode('utf8','surrogateescape') 
'C\udcc3N' 

Это могут быть преобразованы в и из Unicode без потерь:

>>> b'C\xc3N'.decode('utf8','surrogateescape').encode('utf8','surrogateescape') 
b'C\xc3N' 

Но это не может быть напечатано:

>>> print(b'C\xc3N'.decode('utf8','surrogateescape')) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'utf-8' codec can't encode character '\udcc3' in position 1: surrogates not allowed 

Вам нужно будет выяснить, что вы хотите делать с именами файлов с кодировками по умолчанию. Возможно, просто перекодируйте их обратно в исходные байты и декодируйте их с неизвестной заменой. Используйте это для отображения, но сохраните исходное имя для доступа к файлу.

>>> b'C\xc3N'.decode('utf8','replace') 
C�N 

os.walk также может принимать строку байтов и будет возвращать байт строки вместо строк Unicode:

for p,d,f in os.walk(b'.'): 

Затем вы можете расшифровать, как вам нравится.

+3

Я закончил делать 'bad_string.encode ('utf-8', 'surrogateescape'). Decode ('ISO-8859-1')' –

+0

@Collin Anderson Как вы обнаружили возникновение плохой строки, как вы поймали ошибку? – DoTheEvo

3

я в конечном итоге, переходящие в строке байт в os.walk(), который, по-видимому возвращать байты строки вместо неправильных строк Юникода

for root, dirs, files in os.walk(b'.'): 
    print(root)