这是一个与MizardX相似的答案,但是没有明显的问题,即在最坏的情况下,由于添加了块,重复扫描了工作字符串是否换行,从而在最坏的情况下花费了二次时间。
与活动状态解决方案(也似乎是二次方的)相比,在没有空文件的情况下,此操作不会崩溃,并且每个块读取一次,而不是两次。
与产生“尾巴”相比,这是独立的。(但是,如果有的话,“尾巴”是最好的。)
与从末端获取几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
编辑:将map()更改为head()中的itertools.imap()。编辑2:简化的reversed_blocks()。编辑3:避免重新扫描尾部以换行。编辑4:重新编写了reversed_lines(),因为str.splitlines()忽略了最后的'\ n',正如BrianB注意到的(谢谢)。
请注意,在非常老的Python版本中,此处循环中的字符串连接将花费二次时间。至少最近几年的CPython可以自动避免此问题。