【问题标题】:why does file.tell() affect encoding?为什么 file.tell() 会影响编码?
【发布时间】:2016-05-10 02:44:51
【问题描述】:

在读取我的 GBK 编码文件时调用 tell() 会导致对 readline() 的下一次调用引发 UnicodeDecodeError。但是,如果我不调用tell(),它不会引发此错误。

C:\tmp>hexdump badtell.txt

000000: 61 20 6B 0D 0A D2 BB B0-E3                       a k......

C:\tmp>输入 test.py

with open(r'c:\tmp\badtell.txt', "r", encoding='gbk') as f:
    while True:
        pos = f.tell()
        line = f.readline();
        if not line: break
        print(line)

C:\tmp>python test.py

a k

Traceback (most recent call last):
  File "test.py", line 4, in <module>
    line = f.readline();
UnicodeDecodeError: 'gbk' codec can't decode byte 0xd2 in position 0:  incomplete multibyte sequence

当我删除f.tell() 语句时,它成功解码。为什么? 我在Win7/Win10上试过Python3.4/3.5 x64,都一样。

任何一个,任何想法?我应该报告错误吗?

我有一个大文本文件,我很想得到这个大文本的文件位置范围,有解决方法吗?

【问题讨论】:

  • 我有一个大文本文件,我真的希望文件位置范围显示这个大文本的一部分,有解决方法吗?谢谢

标签: python-3.x file-io character-encoding gbk


【解决方案1】:

好的,有一个解决方法,到目前为止它有效:

with open(r'c:\tmp\badtell.txt', "rb") as f:
    while True:
        pos = f.tell()
        line = f.readline();
        if not line: break
        line = line.decode("gbk").strip('\n')
        print(line)

我昨天在这里提交了一个问题:http://bugs.python.org/issue26990

还没有回复

【讨论】:

    【解决方案2】:

    我刚刚在 Linux 上的 Python 3.4 x64 上复制了这个。查看TextIOBase 的文档,我没有看到任何说tell() 的内容会导致读取文件出现问题,因此可能确实是一个错误。

    b'\xd2'.decode('gbk')
    

    给出与您看到的类似的错误,但在您的文件中,该字节后跟字节BB,并且

    b'\xd2\xbb'.decode('gbk')
    

    给出的值等于'\u4e00',而不是错误。

    我找到了一种解决方法,适用于您原始问题中的数据,但不适用于其他数据,正如您后来发现的那样。希望我知道为什么!我在每个tell() 之后调用seek(),并使用tell() 返回的值:

    pos = f.tell()
    f.seek(pos)
    line = f.readline()
    

    f.seek(f.tell()) 的替代方法是使用seek()SEEK_CUR 模式来给出位置。偏移量为 0,这与上面的代码相同:移动到当前位置并获取该位置。

    pos = f.seek(0, io.SEEK_CUR)
    line = f.readline()
    

    【讨论】:

    • 太棒了! f.seek(0, io.SEEK_CUR) 在 python 3.4 x64/win7 上为我工作
    • 事情又变得奇怪了,这一次,seek 做了坏事:
    • C:\tmp>hexdump -r badtell.txt 5B 74 61 67 5F 75 73 65 72 20 74 61 67 5F 47 65 74 4D 65 73 73 61 67 65 20 74 61 67 5F 6D 65 73 73 61 67 65 5D 0D 0A D3 C3 BB A7 CF FB CF A2 3A 20 57 4D 5F 55 53 45 52 20 7E 20 2E 0D 0A 0D 0A 2F 2F 20 54 0D 0A 2F 2F 495 CD F9 C 45 4 4 B1 BE 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A 0D 0A
    • @mfmain 很奇怪,如果我在没有seek() 的情况下使用您的原始代码,那么对于其他文件数据,我不会收到任何错误...不知道为什么
    • 感谢您的帮助,用“rb”打开可以解决问题,它是由 Modules/_io/fileio.c:_io_FileIO_tell_impl() 实现的,我想这是一个简单的方法,但是textio.c:_io_TextIOWrapper_tell_impl() 太复杂了,哎呀,复杂的时候事情就变得棘手了,只是没有时间检查它
    猜你喜欢
    • 2017-06-26
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    • 2016-12-09
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多