Ошибка символа Python os.walk [дубликат]

Очистить и перестроить

. «Чистая» сборки может удалить «мертвую древесину», которая может быть оставлена ​​лежащей рядом с предыдущими сборками, неудачными сборками, неполными сборками и другими проблемами сборки.

В общем случае среда IDE или сборка будет включать в себя некоторую форму «чистой» функции, но это может быть неправильно настроено (например, в ручном файле) или может завершиться неудачей (например, промежуточные или результирующие двоичные файлы - только).

После завершения «очистки» убедитесь, что «чистый» преуспел, и весь сгенерированный промежуточный файл (например, автоматический файл makefile) был успешно удален.

Этот процесс можно рассматривать как конечный вариант, но часто является хорошим первым шагом ; особенно если недавно был добавлен код, связанный с ошибкой (локально или из исходного репозитория).

18
задан Scott 14 February 2014 в 19:16
поделиться

5 ответов

После изучения источника ошибки что-то происходит в подпрограмме listdir C-кода, которая возвращает имена файлов, отличных от unicode, когда они не являются стандартными ascii. Единственное исправление заключается в том, чтобы сделать принудительное декодирование списка каталогов в os.walk, что требует замены os.walk. Эта функция замены работает:

def asciisafewalk(top, topdown=True, onerror=None, followlinks=False):
    """
    duplicate of os.walk, except we do a forced decode after listdir
    """
    islink, join, isdir = os.path.islink, os.path.join, os.path.isdir

    try:
        # Note that listdir and error are globals in this module due
        # to earlier import-*.
        names = os.listdir(top)
        # force non-ascii text out
        names = [name.decode('utf8','ignore') for name in names]
    except os.error, err:
        if onerror is not None:
            onerror(err)
        return

    dirs, nondirs = [], []
    for name in names:
        if isdir(join(top, name)):
            dirs.append(name)
        else:
            nondirs.append(name)

    if topdown:
        yield top, dirs, nondirs
    for name in dirs:
        new_path = join(top, name)
        if followlinks or not islink(new_path):
            for x in asciisafewalk(new_path, topdown, onerror, followlinks):
                yield x
    if not topdown:
        yield top, dirs, nondirs

Добавляя строку: names = [name.decode ('utf8', 'ignore') для имени в именах], все имена соответствуют ascii & amp; unicode, и все работает правильно.

Однако остается большой вопрос - как это можно решить, не прибегая к этому взлому?

5
ответ дан Scott 23 August 2018 в 23:15
поделиться

У меня возникла эта проблема при использовании os.walk в некоторых каталогах с китайскими (юникодными) именами. Я реализовал функцию walk непосредственно следующим образом, которая отлично работала с именами dir / file в unicode.

import os

ft = list(tuple())

def walk(dir, cur):
    fl = os.listdir(dir)
    for f in fl:
        full_path = os.path.join(dir,f)    
        if os.path.isdir(full_path):
            walk(full_path, cur)
        else:
            path, filename = full_path.rsplit('/',1)
            ft.append((path, filename, os.path.getsize(full_path)))
0
ответ дан jcz 23 August 2018 в 23:15
поделиться

Я могу воспроизвести поведение os.listdir(): os.listdir(unicode_name) возвращает недоказуемые записи в виде байтов на Python 2.7:

>>> import os
>>> os.listdir(u'.')
[u'abc', '<--\x8b-->']

Обратите внимание: второе имя является байтовой, несмотря на аргумент listdir(), являющийся Строка Unicode.

Тем не менее остается большой вопрос - как это можно решить, не прибегая к этому взлому?

Python 3 разрешает недоказуемые байты (используя файловую систему кодирование символов) байтов в именах файлов с помощью обработчика ошибок surrogateescape ( os.fsencode/os.fsdecode ). См. PEP-383: Non-decodable Bytes в системных символьных интерфейсах :

>>> os.listdir(u'.')
['abc', '<--\udc8b-->']

Обратите внимание: обе строки являются Unicode (Python 3). И обработчик ошибок surrogateescape использовался для второго имени. Чтобы вернуть исходные байты:

>>> os.fsencode('<--\udc8b-->')
b'<--\x8b-->'

В Python 2 используйте строки Unicode для имен файлов в Windows (Unicode API), OS X (применяется utf-8) и используйте bytestrings в Linux и других системах .

7
ответ дан jfs 23 August 2018 в 23:15
поделиться

\ x8 не является допустимым символом кодирования utf-8. os.path ожидает, что имена файлов будут в utf-8. Если вы хотите получить доступ к недопустимым именам файлов, вам необходимо передать os.path.walk стартовую строку, отличную от unicode; таким образом, модуль os не будет выполнять декодирование utf8. Вам нужно будет сделать это самостоятельно и решить, что делать с именами файлов, которые содержат неправильные символы.

I.e.:

for root, dirs, files in os.walk(startpath.encode('utf8')):
1
ответ дан ondra 23 August 2018 в 23:15
поделиться

Правильно, я просто потратил некоторое время на сортировку этой ошибки, и ответы на словари здесь не попадают в основную проблему:

Проблема в том, что если вы передаете строку юникода в os.walk (), то os.walk начинает получать unicode обратно из os.listdir () и пытается сохранить его как ASCII (следовательно, ошибка ascii-декодирования). Когда он нажимает на unicode только специальный символ, который str () не может перевести, он выдает исключение.

Решение состоит в том, чтобы заставить исходный путь, по которому вы проходите, os.walk, быть регулярной строкой, т.е. os.walk (ул (somepath)). Это означает, что os.listdir возвращает обычные байтоподобные строки, и все работает так, как должно.

Вы можете воспроизвести эту проблему (и показать ее решения) тривиально:

  1. Перейдите в bash в какой-то каталог и запустите touch $(echo -e "\x8b\x8bThis is a bad filename"), который сделает некоторые тестовые файлы.
  2. Теперь запустите следующий код Python (iPython Qt удобен для этого) в той же папке:
    l = []
    for root,dir,filenames in os.walk(unicode('.')):
        l.extend([ os.path.join(root, f) for f in filenames ])
    print l
    

И вы получите UnicodeDecodeError.

  1. Теперь попробуйте запустить:
    l = []
    for root,dir,filenames in os.walk('.'):
        l.extend([ os.path.join(root, f) for f in filenames ])
    print l
    

Нет ошибки, и вы получаете распечатать!

Таким образом, безопасный способ в Python 2.x состоит в том, чтобы убедиться, что вы только передаете исходный текст в os.walk (). Вы абсолютно не должны пропускать unicode или вещи, которые могут быть unicode к нему, потому что os.walk затем задохнется, когда внутреннее преобразование ascii завершится с ошибкой.

8
ответ дан Will Rouesnel 23 August 2018 в 23:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: