我收到此错误:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe0 in position 4: ordinal not in range(128)
我尝试设置许多不同的编解码器(在标题中,如# -*- coding: utf8 -*-),甚至使用u“ string”,但它仍然出现。
# -*- coding: utf8 -*-
我该如何解决?
编辑:我不知道导致此问题的实际字符,但是由于这是一个递归浏览文件夹的程序,因此它必须找到名称中带有奇怪字符的文件
码:
# -*- coding: utf8 -*- # by TerabyteST ########################### # Explores given path recursively # and finds file which size is bigger than the set treshold import sys import os class Explore(): def __init__(self): self._filelist = [] def exploreRec(self, folder, treshold): print folder generator = os.walk(folder + "/") try: content = generator.next() except: return folders = content[1] files = content[2] for n in folders: if "$" in n: folders.remove(n) for f in folders: self.exploreRec(u"%s/%s"%(folder, f), treshold) for f in files: try: rawsize = os.path.getsize(u"%s/%s"%(folder, f)) except: print "Error reading file %s"%u"%s/%s"%(folder, f) continue mbsize = rawsize / (1024 * 1024.0) if mbsize >= treshold: print "File %s is %d MBs!"%(u"%s/%s"%(folder, f), mbsize)
错误:
Traceback (most recent call last): File "<pyshell#19>", line 1, in <module> a.exploreRec("C:", 100) File "D:/Python/Explorator/shitfinder.py", line 35, in exploreRec print "Error reading file %s"%u"%s/%s"%(folder, f) UnicodeDecodeError: 'ascii' codec can't decode byte 0xe0 in position 4: ordinal not in range(128)
这是使用显示的 print repr("Error reading file %s"%u"%s/%s"%(folder.decode('utf-8','ignore'), f.decode('utf-8','ignore')))
print repr("Error reading file %s"%u"%s/%s"%(folder.decode('utf-8','ignore'), f.decode('utf-8','ignore')))
>>> a = Explore() >>> a.exploreRec("C:", 100) File C:/Program Files/Ableton/Live 8.0.4/Resources/DefaultPackages/Live8Library_v8.2.alp is 258 MBs! File C:/Program Files/Adobe/Reader 9.0/Setup Files/{AC76BA86-7AD7-1040-7B44-A90000000001}/Data1.cab is 114 MBs! File C:/Program Files/Microsoft Games/Age of Empires III/art/Art1.bar is 393 MBs! File C:/Program Files/Microsoft Games/Age of Empires III/art/art2.bar is 396 MBs! File C:/Program Files/Microsoft Games/Age of Empires III/art/art3.bar is 228 MBs! File C:/Program Files/Microsoft Games/Age of Empires III/Sound/Sound.bar is 273 MBs! File C:/ProgramData/Microsoft/Search/Data/Applications/Windows/Windows.edb is 162 MBs! REPR: u"Error reading file C:/ProgramData/Microsoft/Windows/GameExplorer/{1B4801C1-CA86-487E-8347-B26F1CCB2F75}/SupportTasks/0/Sito web di Mirror's Edge.lnk" END REPR: Error reading file C:/ProgramData/Microsoft/Windows/GameExplorer/{1B4801C1-CA86-487E-8347-B26F1CCB2F75}/SupportTasks/0/Sito web di Mirror's Edge.lnk REPR: u"Error reading file C:/ProgramData/Microsoft/Windows/GameExplorer/{1B4801C1-CA86-487E-8347-B26F1CCB2F75}/SupportTasks/1/Contenuti scaricabili di Mirror's Edge.lnk" END REPR: Error reading file C:/ProgramData/Microsoft/Windows/GameExplorer/{1B4801C1-CA86-487E-8347-B26F1CCB2F75}/SupportTasks/1/Contenuti scaricabili di Mirror's Edge.lnk REPR: u'Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Google Talk/Supporto/Modalitiagnostica di Google Talk.lnk' END REPR: Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Google Talk/Supporto/Modalitiagnostica di Google Talk.lnk REPR: u'Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Microsoft SQL Server 2008/Strumenti di configurazione/Segnalazione errori e utilizzo funzionaliti SQL Server.lnk' END REPR: Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Microsoft SQL Server 2008/Strumenti di configurazione/Segnalazione errori e utilizzo funzionaliti SQL Server.lnk REPR: u'Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Mozilla Firefox/Mozilla Firefox ( Modalitrovvisoria).lnk' END REPR: Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Mozilla Firefox/Mozilla Firefox ( Modalitrovvisoria).lnk REPR: u'Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Mozilla Firefox 3.6 Beta 1/Mozilla Firefox 3.6 Beta 1 ( Modalitrovvisoria).lnk' END REPR: Error reading file C:/ProgramData/Microsoft/Windows/Start Menu/Programs/Mozilla Firefox 3.6 Beta 1/Mozilla Firefox 3.6 Beta 1 ( Modalitrovvisoria).lnk Traceback (most recent call last): File "<pyshell#21>", line 1, in <module> a.exploreRec("C:", 100) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) File "D:/Python/Explorator/shitfinder.py", line 30, in exploreRec self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold) UnicodeDecodeError: 'ascii' codec can't decode byte 0x99 in position 78: ordinal not in range(128) >>>
我们无法猜测您想做什么,您的代码中没有什么,“设置许多不同的编解码器”意味着什么,您“字符串”应该为您做什么。
请将您的代码更改为其初始状态,以使其尽可能地反映您要执行的操作,再次运行它,然后编辑问题以提供(1)完整的回溯和错误消息,以及(2)摘录包括脚本中出现在回溯中的最后一条语句(3)对代码要执行的操作的简短描述(4)您正在运行的Python版本。
在详细信息添加到问题后进行编辑:
(0)让我们尝试对失败的语句进行一些转换:
原始语言: print "Error reading file %s"%u"%s/%s"%(folder, f) 添加空格以减少模糊性: print "Error reading file %s" % u"%s/%s" % (folder, f) 添加括号以强调评估顺序: print ("Error reading file %s" % u"%s/%s") % (folder, f) 评估括号中的(常数)表达式: print u"Error reading file %s/%s" % (folder, f)
print "Error reading file %s"%u"%s/%s"%(folder, f)
print "Error reading file %s" % u"%s/%s" % (folder, f)
print ("Error reading file %s" % u"%s/%s") % (folder, f)
print u"Error reading file %s/%s" % (folder, f)
那真的是您想要的吗?建议:使用更好的方法构造路径ONCE(请参阅下面的点(2))。
(1)通常,用于repr(foo)或"%r" % foo用于诊断。这样,您的诊断代码就不太可能引起异常(如此处所发生的那样),并且可以避免歧义。print repr(folder), repr(f)在尝试获取大小,重新运行并报告之前,请插入该语句。
repr(foo)
"%r" % foo
print repr(folder), repr(f)
(2)不要通过u"%s/%s" % (folder, filename)…使用来建立路径os.path.join(folder, filename)
u"%s/%s" % (folder, filename)
os.path.join(folder, filename)
(3)别无其他,检查已知问题。为了避免出现未知问题,请执行以下操作:
try: some_code() except ReasonForBaleOutError: continue except: # something's gone wrong, so get diagnostic info print repr(interesting_datum_1), repr(interesting_datum_2) # ... and get traceback and error message raise
一种更复杂的方法是使用日志记录而不是打印,但是与不知道发生了什么相比,上述方法要好得多。
*在rtm(“ os.walk”)之后进行 *进一步的编辑 ,记住旧的图例,然后重新读取代码:
(4)os.walk()遍历整棵树;您无需递归调用它。
(5)如果将unicode字符串传递给os.walk(),结果(路径,文件名)将报告为unicode。您并不需要所有的东西。然后,您只需要选择显示unicode结果的方式即可。
(6)删除其中带有“ $”的路径:您必须就地修改列表,但是这样做很危险。尝试这样的事情:
for i in xrange(len(folders), -1, -1): if '$' in folders[i]: del folders[i]
(7)通过结合文件夹名称和文件名称来引用文件。您正在使用ORIGINAL文件夹名称;当您退出递归时,这将不起作用;您需要使用content[0]os.walk报告的当前丢弃的值。
content[0]
(8)您应该使用一些非常简单的方法:
for folder, subfolders, filenames in os.walk(unicoded_top_folder):
generator = os.walk(...); try: content = generator.next()如果您generator.next()将来需要这样做,则无需使用etc和BTW ,except StopIteration而只需使用裸机即可。
generator = os.walk(...); try: content = generator.next()
generator.next()
except StopIteration
(9)如果调用方提供了一个不存在的文件夹,则不会引发异常,它什么也不做。如果提供的文件夹存在但为空,则同上。如果需要区分这两种情况,则需要自己进行额外的测试。
回复来自OP的评论: “”谢谢,请阅读第一篇文章中显示的信息repr()。我不知道为什么它打印了这么多不同的项目,但看起来它们都有问题。它们之间的共同点是它们是.ink文件。这可能是问题所在吗?此外,在最后一个文件中,Firefox会打印(Modalitrovvisoria),而资源管理器中的真实文件名包含(Modalitàprovvisoria)“” ”
(10)嗯,这不是“ .INK” .lower(),而是“ .LNK” .lower()…也许您需要更改正在阅读的字体。
(11)“问题”文件名全都以“ .lnk”结尾的事实,可能与os.walk()有关,和/或Windows对这些文件名做了一些特殊处理。
(12)在此重复我用来生成该输出的Python语句,并引入了一些空白:
print repr( "Error reading file %s" \ % u"%s/%s" % ( folder.decode('utf-8','ignore'), f.decode('utf-8','ignore') ) )
似乎您尚未阅读,理解或忽略了我在对另一个答案(以及答案的答复)的评论中给您的建议: UTF-8与Windows文件中文件名的上下文无关系统。
我们对文件夹和f到底指的是什么感兴趣。您试图通过使用UTF-8对其进行解码,从而践踏了所有证据。您已经使用“忽略”选项使混淆变得更加复杂。如果您使用了“替换”选项,则会看到“((Modalit \ ufffdrovvisoria)””。“忽略”选项在调试中没有位置。
在任何情况下,某些文件名都有某种错误,但使用“ ignore”选项似乎不会丢失字符(或看上去不会被篡改),这一事实是可疑的。
print repr(folder), repr(f)您不理解“”“的哪一部分插入语句”“”?您需要做的就是这样:
print "Some meaningful text" # "error reading file" isn't print "folder:", repr(folder) print "f:", repr(f)
(13)根据回溯判断,您似乎还在代码的其他地方引入了UTF-8: self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold)
self.exploreRec(("%s/%s"%(folder, f)).encode("utf-8"), treshold)
我想指出的是,您仍然不知道folder和f是指str对象还是unicode对象,两个答案表明它们很可能是str对象,因此为什么要引入blahbah.encode()?
一个更一般的观点:在更改脚本之前,尝试了解您的问题所在。尝试尝试每条建议并加上几乎为零的有效调试技术并不是解决问题的办法。
(14)当您再次运行脚本时,您可能希望通过在C:\的某个子集上运行来减少输出的数量,尤其是如果您按照我最初的建议对所有文件名进行调试打印,不仅是错误的错误(知道非错误的错误看起来可能有助于理解问题)。
回应Bryan McLemore的“清理”功能:
(15)这是一个带注释的交互式会话,它说明os.walk()和非ASCII文件名实际发生的情况:
C:\junk\terabytest>dir [snip] Directory of C:\junk\terabytest 20/11/2009 01:28 PM <DIR> . 20/11/2009 01:28 PM <DIR> .. 20/11/2009 11:48 AM <DIR> empty 20/11/2009 01:26 PM 11 Hašek.txt 20/11/2009 01:31 PM 1,419 tbyte1.py 29/12/2007 09:33 AM 9 Ð.txt 3 File(s) 1,439 bytes [snip] C:\junk\terabytest>\python26\python Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] onwin32 Type "help", "copyright", "credits" or "license" for more information. >>> from pprint import pprint as pp >>> import os
os.walk(unicode_string)->产生unicode对象
>>> pp(list(os.walk(ur"c:\junk\terabytest"))) [(u'c:\\junk\\terabytest', [u'empty'], [u'Ha\u0161ek.txt', u'tbyte1.py', u'\xd0.txt']), (u'c:\\junk\\terabytest\\empty', [], [])]
os.walk(str_string)->产生str对象
>>> pp(list(os.walk(r"c:\junk\terabytest"))) [('c:\\junk\\terabytest', ['empty'], ['Ha\x9aek.txt', 'tbyte1.py', '\xd0.txt']), ('c:\\junk\\terabytest\\empty', [], [])]
cp1252是我希望在系统上使用的编码…
>>> u'\u0161'.encode('cp1252') '\x9a' >>> 'Ha\x9aek'.decode('cp1252') u'Ha\u0161ek'
如预期那样,使用UTF-8解码str无法正常工作
>>> 'Ha\x9aek'.decode('utf8') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\python26\lib\encodings\utf_8.py", line 16, in decode return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError: 'utf8' codec can't decode byte 0x9a in position 2: unexpected code byte
可以使用latin1解码任何随机字节串,而不会出错
>>> 'Ha\x9aek'.decode('latin1') u'Ha\x9aek'
但是U + 009A是控制字符(单字符输入),即无意义的乱码;绝对与正确答案无关
>>> unicodedata.name(u'\u0161') 'LATIN SMALL LETTER S WITH CARON' >>>
(16)该示例显示了在默认字符集中可以表示该字符的情况;如果不是,会发生什么?这是一个包含CJK表意文字的文件名示例(这次使用IDLE),在我的默认字符集中肯定无法表示这些文件:
IDLE 2.6.4 >>> import os >>> from pprint import pprint as pp
repr(Unicode结果)看起来不错
>>> pp(list(os.walk(ur"c:\junk\terabytest\chinese"))) [(u'c:\\junk\\terabytest\\chinese', [], [u'nihao\u4f60\u597d.txt'])]
并且Unicode在IDLE中显示得很好:
>>> print list(os.walk(ur"c:\junk\terabytest\chinese"))[0][2][0] nihao你好.txt
str结果显然是通过使用.encode(无论如何,“替换”)产生的-并不是很有用,例如,您不能通过将其作为文件名传递来打开文件。
>>> pp(list(os.walk(r"c:\junk\terabytest\chinese"))) [('c:\\junk\\terabytest\\chinese', [], ['nihao??.txt'])]
因此得出的结论是,为了获得最佳结果,应该将一个unicode字符串传递给os.walk(),并处理任何显示问题。