. «Чистая» сборки может удалить «мертвую древесину», которая может быть оставлена лежащей рядом с предыдущими сборками, неудачными сборками, неполными сборками и другими проблемами сборки.
В общем случае среда IDE или сборка будет включать в себя некоторую форму «чистой» функции, но это может быть неправильно настроено (например, в ручном файле) или может завершиться неудачей (например, промежуточные или результирующие двоичные файлы - только).
После завершения «очистки» убедитесь, что «чистый» преуспел, и весь сгенерированный промежуточный файл (например, автоматический файл makefile) был успешно удален.
Этот процесс можно рассматривать как конечный вариант, но часто является хорошим первым шагом ; особенно если недавно был добавлен код, связанный с ошибкой (локально или из исходного репозитория).
После изучения источника ошибки что-то происходит в подпрограмме 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, и все работает правильно.
Однако остается большой вопрос - как это можно решить, не прибегая к этому взлому?
У меня возникла эта проблема при использовании 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)))
Я могу воспроизвести поведение os.listdir()
: os.listdir(unicode_name)
возвращает недоказуемые записи в виде байтов на Python 2.7:
>>> import os
>>> os.listdir(u'.')
[u'abc', '<--\x8b-->']
Обратите внимание: второе имя является байтовой, несмотря на аргумент listdir()
, являющийся Строка Unicode.
Тем не менее остается большой вопрос - как это можно решить, не прибегая к этому взлому?
blockquote>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 и других системах .
\ 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')):
Правильно, я просто потратил некоторое время на сортировку этой ошибки, и ответы на словари здесь не попадают в основную проблему:
Проблема в том, что если вы передаете строку юникода в os.walk (), то os.walk начинает получать unicode обратно из os.listdir () и пытается сохранить его как ASCII (следовательно, ошибка ascii-декодирования). Когда он нажимает на unicode только специальный символ, который str () не может перевести, он выдает исключение.
Решение состоит в том, чтобы заставить исходный путь, по которому вы проходите, os.walk, быть регулярной строкой, т.е. os.walk (ул (somepath)). Это означает, что os.listdir возвращает обычные байтоподобные строки, и все работает так, как должно.
Вы можете воспроизвести эту проблему (и показать ее решения) тривиально:
touch $(echo -e "\x8b\x8bThis is a bad filename")
, который сделает некоторые тестовые файлы. l = []
for root,dir,filenames in os.walk(unicode('.')):
l.extend([ os.path.join(root, f) for f in filenames ])
print l
И вы получите UnicodeDecodeError.
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 завершится с ошибкой.