我收到错误:
'ascii' codec can't decode byte 0x8b in position 14: ordinal not in range(128)
当试图做 os.walk 时。发生错误是因为目录中的某些文件中包含 0x8b(非 utf8)字符。这些文件来自 Windows 系统(因此是 utf-16 文件名),但我已将文件复制到 Linux 系统并使用 python 2.7(在 Linux 中运行)来遍历目录。
我尝试将 unicode 起始路径传递给 os.walk,它生成的所有文件和目录都是 unicode 名称,直到它变成非 utf8 名称,然后由于某种原因,它不会转换这些名称到 unicode,然后代码阻塞在 utf-16 名称上。除了手动查找和更改所有令人反感的名称之外,还有什么方法可以解决这个问题?
如果在python2.7中没有解决方案,是否可以在python3中编写一个脚本来遍历文件树并通过将它们转换为utf-8(通过删除非utf8字符)来修复错误的文件名?注:除了 0x8b 之外,名称中还有许多非 utf8 字符,因此它需要以一般方式工作。
更新:0x8b 仍然只是一个 btye char(只是无效的 ascii)这一事实使它更加令人费解。我已验证将此类字符串转换为 unicode 存在问题,但可以直接创建 unicode 版本。也就是说:
>>> test = 'a string \x8b with non-ascii'
>>> test
'a string \x8b with non-ascii'
>>> unicode(test)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0x8b in position 9: ordinal not in range(128)
>>>
>>> test2 = u'a string \x8b with non-ascii'
>>> test2
u'a string \x8b with non-ascii'
这是我得到的错误的回溯:
80. for root, dirs, files in os.walk(unicode(startpath)):
File "/usr/lib/python2.7/os.py" in walk
294. for x in walk(new_path, topdown, onerror, followlinks):
File "/usr/lib/python2.7/os.py" in walk
294. for x in walk(new_path, topdown, onerror, followlinks):
File "/usr/lib/python2.7/os.py" in walk
284. if isdir(join(top, name)):
File "/usr/lib/python2.7/posixpath.py" in join
71. path += '/' + b
Exception Type: UnicodeDecodeError at /admin/casebuilder/company/883/
Exception Value: 'ascii' codec can't decode byte 0x8b in position 14: ordinal not in range(128)
问题的根源出现在从listdir返回的文件列表中(在os.walk的第276行):
names = listdir(top)
字符数 > 128 的名称将作为非 unicode 字符串返回。
请您参考如下方法:
是的,我只是花了一些时间来整理这个错误,这里更冗长的答案并没有解决根本问题:
问题是,如果你将一个 unicode 字符串 传入 os.walk(),那么 os.walk 开始从 os.listdir() 获取 unicode 并尝试将其保留为 ASCII(因此'ascii' 解码错误)。当它遇到 str() 无法翻译的仅 unicode 特殊字符时,它会抛出异常。
解决方案是强制传递给 os.walk 的起始路径为常规字符串 - 即 os.walk(str(somepath))。这意味着 os.listdir 返回常规的类似字节的字符串,并且一切正常。
你可以像这样简单地重现这个问题(并展示它的解决方案):
进入某个目录中的 bash 并运行
touch $(echo -e "\x8b\x8bThis is a bad filename")
这将生成一些测试文件。现在在同一目录中运行以下 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。
现在尝试运行:
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 转换失败时阻塞。