使用python 3以健壮的方式解析文件

时间:2014-07-14 16:22:48

标签: python python-3.x

我有一个日志文件,我需要逐行检查,显然它包含一些“坏字节”。我收到的错误信息如下:

  

UnicodeDecodeError:'utf-8'编解码器无法解码位置9的字节0xb0:无效的起始字节

我已经能够将问题删除到包含以下行的文件“log.test”:

Message: \260

(至少这是它在我的Emacs中的显示方式。)

我有一个文件“demo_error.py”,如下所示:

import sys
with open(sys.argv[1], 'r') as lf:
    for i, l in enumerate(lf):
        print(i, l.strip())

然后我从命令行运行:

  

$ python3 demo_error.py log.test

完整的追溯是:

Traceback (most recent call last):
  File "demo_error.py", line 5, in <module>
    for i, l in enumerate(lf):
  File     "/usr/local/Cellar/python3/3.4.0/Frameworks/Python.framework/Versions/3.4/lib/python3.4/codecs.py", line 313, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb0 in position 13: invalid start byte

我的预感是我必须以某种方式指定一个更通用的编解码器(例如“raw ascii”) - 但我不太确定如何做到这一点。

请注意,这在Python 2.7中确实不是问题。

只是为了明确我的观点:我不介意对相关的行进行例外处理 - 然后我可以简单地丢弃该行。问题是异常似乎发生在“for”循环本身,这使得特定行的特殊处理变得不可能。

3 个答案:

答案 0 :(得分:4)

显然你的文件不包含有效的UTF-8(这是默认编码)。 如果你知道,使用了什么编码(例如iso-8859-1,这是默认的python2),你可以在打开时使用

指定它
open(sys.argv[1], mode='r', encoding='iso-8859-1')

如果编码未知或无效,则可以将文件打开为二进制文件。

open(sys.argv[1], mode='rb')

这将使内容可以作为字节访问,而不是试图将它们解释为字符。

答案 1 :(得分:4)

您也可以使用codecs模块。使用codecs.open()函数时,可以使用 errors 参数指定它如何处理错误:

codecs.open(filename, mode[, encoding[, errors[, buffering]]])

错误参数可以是几个不同的关键字之一,用于指定Python在尝试解码对当前编码无效的字符时的行为方式。您可能对 codecs.ignore_errors codecs.replace_errors 最感兴趣,这会导致无效字符被忽略或被默认字符替换。< / p>

当您知道有损坏的数据时,即使您指定了正确的编码也会引发UnicodeDecodeError,此方法可能是一个不错的选择。

示例:

with codecs.open('file.txt', mode='r', errors='ignore'):
    # ...stuff...
    # Even if there is corrupt data and invalid characters for the default
    # encoding, this open() will still succeed

答案 2 :(得分:3)

在python&lt; = 2.7中,strings(str)是8位字符的数组。因此,当读取由8位字符或字节组成的文件时,无论实际编码是什么,都可以毫无问题地获得字节。简单地说,你可能会用错误的表示来阅读它们,但它永远不会抛出任何异常。

在python&gt; = 3中,字符串是unicode字符串(每个字符16位)。因此,当读取文件时,python必须解码该文件,并且默认情况下它使用系统编码 - 不一定是UTF-8 。在你的情况下,它似乎假设UTF-8编码,当你的日志文件不是UTF-8编码所以例外。

如果不确定编码,您可以合理地尝试使用ISO-8859-1

open(sys.argv[1], 'r', encoding='iso-8859-1')