Для повышения эффективности работы с очень большими файлами (обычно в ситуациях с лог-файлами, когда вы можете использовать tail), вы, как правило, хотите избегать чтения всего файла (даже если вы делаете это, не считывая весь файл сразу в память) Вам нужно как-то отработать смещение в строках, а не в символах. Одной из возможностей является чтение в обратном порядке с помощью функции seek () char за char, но это очень медленно. Вместо этого лучше обрабатывать в больших блоках.
У меня есть служебная функция, которую я недавно написал для чтения файлов в обратном направлении, которую можно использовать здесь.
import os, itertools
def rblocks(f, blocksize=4096):
"""Read file as series of blocks from end of file to start.
The data itself is in normal order, only the order of the blocks is reversed.
ie. "hello world" -> ["ld","wor", "lo ", "hel"]
Note that the file must be opened in binary mode.
"""
if 'b' not in f.mode.lower():
raise Exception("File must be opened using binary mode.")
size = os.stat(f.name).st_size
fullblocks, lastblock = divmod(size, blocksize)
# The first(end of file) block will be short, since this leaves
# the rest aligned on a blocksize boundary. This may be more
# efficient than having the last (first in file) block be short
f.seek(-lastblock,2)
yield f.read(lastblock)
for i in range(fullblocks-1,-1, -1):
f.seek(i * blocksize)
yield f.read(blocksize)
def tail(f, nlines):
buf = ''
result = []
for block in rblocks(f):
buf = block + buf
lines = buf.splitlines()
# Return all lines except the first (since may be partial)
if lines:
result.extend(lines[1:]) # First line may not be complete
if(len(result) >= nlines):
return result[-nlines:]
buf = lines[0]
return ([buf]+result)[-nlines:]
f=open('file_to_tail.txt','rb')
for line in tail(f, 20):
print line
[Редактировать] Добавлена более конкретная версия (избегать необходимости дважды)