在Python 3中从文件末尾开始查找

5

Python 3 中的一个变化是在普通文本模式下删除了从文件末尾查找的能力。那么,通常接受的替代方案是什么呢?

例如,在 Python 2.7 中,我会输入 file.seek(-3,2)。

我已经了解了一些他们为什么这样做的原因,所以请不要只链接到 PEP。我知道使用 'rb' 可以允许我查找,但这会使我的文本文件以错误的格式读取。


对于单字节编码,您总是可以手动解码数据。 - Martijn Pieters
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Isuru Madusanka
@IsuruMadusanka:在所有Python 3版本中都可以使用seek。不可用的是从末尾开始相对查找。3.1也不例外。 - Martijn Pieters
1个回答

6
在Python 2中,读取文件数据时没有进行解码。向后查找和多字节编码不兼容(你无法知道下一个字符从哪里开始),这就是为什么它在Python 3中被禁用的原因。
你仍然可以通过TextIOBase.buffer属性在底层缓冲区对象上寻找,但此时你需要重新附加一个新的TextIOBase包装器,因为当前包装器将不再知道它所处的位置:
import io

file.buffer.seek(-3, 2)
file = io.TextIOWrapper(
    file.buffer, encoding=file.encoding, errors=file.errors,
    newline=file.newlines)

我已将所有编码和行处理信息复制到 io.TextIOWrapper() 对象 中。
请注意,对于 UTF-16、UTF-32、UTF-8 和其他多字节编解码器,这种解码可能会出现错误。
演示:
>>> import io
>>> with open('demo.txt', 'w') as out:
...     out.write('Demonstration\nfor seeking from the end')
... 
38
>>> with open('demo.txt') as inf:
...     print(inf.readline())
...     inf.buffer.seek(-3, 2)
...     inf = io.TextIOWrapper(inf.buffer)
...     print(inf.readline())
... 
Demonstration

35
end

你可以将这个功能封装在一个实用函数中:
import io

def textio_seek(fobj, amount, whence=0):
    fobj.buffer.seek(amount, whence)
    return io.TextIOWrapper(
        fobj.buffer, encoding=fobj.encoding, errors=fobj.errors,
        newline=fobj.newlines)

并将其用作:

with open(somefile) as file:
    # ...

    file = textio_seek(file, -2, 3)

    # ...

使用文件对象作为上下文管理器仍然有效,因为原始文件对象引用仍附加在原始文件缓冲区对象上,因此仍可用于关闭文件。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接