这里有一个类似于 MizardX 的答案,但没有明显的问题,即在添加块时重复重新扫描工作字符串以寻找换行符,在最坏的情况下花费二次时间。
与 Active State 解决方案(也似乎是二次的)相比,这不会在给定一个空文件的情况下崩溃,并且每个块读取一次而不是两次。
与生成“尾巴”相比,这是独立的。 (但如果你有'尾巴'是最好的。)
与从末尾抓取几 kB 并希望它足够,这适用于任何行长。
import os
def reversed_lines(file):
"Generate the lines of file in reverse order."
part = ''
for block in reversed_blocks(file):
for c in reversed(block):
if c == '\n' and part:
yield part[::-1]
part = ''
part += c
if part: yield part[::-1]
def reversed_blocks(file, blocksize=4096):
"Generate blocks of file's contents in reverse order."
file.seek(0, os.SEEK_END)
here = file.tell()
while 0 < here:
delta = min(blocksize, here)
here -= delta
file.seek(here, os.SEEK_SET)
yield file.read(delta)
按要求使用:
from itertools import islice
def check_last_10_lines(file, key):
for line in islice(reversed_lines(file), 10):
if line.rstrip('\n') == key:
print 'FOUND'
break
编辑: 将 head() 中的 map() 更改为 itertools.imap()。 编辑 2: 简化了 reversed_blocks()。 编辑 3: 避免重新扫描尾部以查找换行符。 编辑 4: 重写了 reversed_lines(),因为 str.splitlines() 忽略了结尾的 '\n',正如 BrianB 注意到的那样(谢谢)。
请注意,在非常旧的 Python 版本中,此处循环中的字符串连接将花费二次时间。至少最近几年的 CPython 自动避免了这个问题。