【问题标题】:UnicodeDecodeError: unexpected end of dataUnicodeDecodeError:数据意外结束
【发布时间】:2013-08-23 20:09:10
【问题描述】:

我有一个巨大的文本文件要打开。
我正在分块读取文件,避免与一次读取太多文件相关的内存问题。

代码 sn-p:

def open_delimited(fileName, args):

    with open(fileName, args, encoding="UTF16") as infile:
        chunksize = 10000
        remainder = ''
        for chunk in iter(lambda: infile.read(chunksize), ''):
            pieces = re.findall(r"(\d+)\s+(\d+_\d+)", remainder + chunk)
            for piece in pieces[:-1]:
                yield piece
            remainder = '{} {} '.format(*pieces[-1]) 
        if remainder:
            yield remainder

代码抛出错误UnicodeDecodeError: 'utf16' codec can't decode bytes in position 8190-8191: unexpected end of data

我尝试了UTF8 并得到了错误UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 0: invalid start byte

latin-1iso-8859-1 引发错误IndexError: list index out of range

输入文件示例:

b'\xff\xfe1\x000\x000\x005\x009\x00\t\x001\x000\x000\x005\x009\x00_\x009\x007\x004\x007\x001\x007\x005\x003\x001\x000\x009\x001\x00\t\x00\t\x00P\x00o\x00s\x00t\x00\t\x001\x00\t\x00H\x00a\x00p\x00p\x00y\x00 \x00B\x00i\x00r\x00t\x00h\x00d\x00a\x00y\x00\t\x002\x000\x001\x001\x00-\x000\x008\x00-\x002\x004\x00 \x00'

我还要提到我有几个这样的大文本文件。
UTF16 对其中许多文件都适用,但在特定文件上却失败了。

有办法解决这个问题吗?

【问题讨论】:

  • 如果您的输入文件 UTF-16(尽管被截断),那么Latin1 或UTF-8 肯定不起作用。
  • 我们可以看看你的输入文件的样本吗?然后至少我们可以尝试猜测使用的编码。将文件读取为二进制文件,然后打印出来。 print(open(fileName, 'rb').read(120)) 应该足够我们合作了。
  • @MartijnPieters 我添加了输入文件的示例。
  • 那绝对是 UTF16。如果该数据在某处损坏,我们几乎无法修复它。您可以尝试不同的块大小,也许TextIOWrapper.read() 中有一个错误,它最终会部分读取代理对。我推荐 2 的幂。例如,16384 是 2**14。
  • 无论如何,尝试使用任何其他编解码器都行不通。

标签: unicode python-3.x


【解决方案1】:

要忽略损坏的数据(可能导致数据丢失),请在 open() 调用上设置 errors='ignore'

with open(fileName, args, encoding="UTF16", errors='ignore') as infile:

open() function documentation 声明:

  • 'ignore' 忽略错误。请注意,忽略编码错误可能会导致数据丢失。

这并不意味着您可以从遇到的明显数据损坏中恢复。

为了说明,假设在您的文件中某处删除或添加了一个字节。 UTF-16 是每个字符使用 2 个字节的编解码器。如果有一个字节丢失或多余,那么所有跟在丢失或多余字节后面的字节对都将不对齐。

这可能会导致进一步解码出现问题,不一定立即出现。 UTF-16 中有一些代码点是非法的,但通常是因为它们与另一个字节对结合使用;您的异常是针对此类无效代码点引发的。但在该点之前可能有成百上千个字节对是有效的 UTF-16,即使不是清晰的文本。

【讨论】:

  • 我尝试了errors='ignore' 并得到了remainder = '{} {} '.format(*pieces[-1]) IndexError: list index out of range
  • 对,因为现在你显然会得到一个 re.findall() 返回根本没有匹配项的块。那就是忽略无效字符的风险;如果您的文件中缺少 一个 字节,则 UTF-16 解码现在可能无法读取;在这种情况下,实际上无法检测到 what 字节丢失,并且您看到的异常可能远远超过文件损坏。
【解决方案2】:

我正在做同样的事情(以块的形式读取许多大文本文件)并且在其中一个文件中遇到了同样的错误:

Traceback (most recent call last):
  File "wordcount.py", line 128, in <module>
    decodedtext = rawtext.decode('utf8')
  File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc2 in position 9999999: unexpected end of data

这是我发现的:问题是一个特定的 Unicode 序列 (\xc2\xa0\xc2\xa0) 跨越两个块。因此,该序列被拆分并变得无法解码。以下是我的解决方法:

# read text
rawtext = file.read(chunksize)

# fix splited end
if chunknumber < totalchunks:
    while rawtext[-1] != ' ':
        rawtext = rawtext + file.read(1)

# decode text
decodedtext = rawtext.decode('utf8')

这也解决了当单词跨越两个块时被切成两半的更普遍的问题。

【讨论】:

    【解决方案3】:

    当您读/写 io.StringIO 对象而不是 io.BytesIO 时,这也可能在 Python 3 中发生

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-28
      • 1970-01-01
      • 2014-05-13
      • 2019-04-04
      • 2019-02-05
      • 1970-01-01
      • 2021-10-13
      相关资源
      最近更新 更多