Aquí hay una respuesta como la de MizardX, pero sin su aparente problema de tomar el tiempo cuadrático en el peor de los casos, al volver a escanear la cadena de trabajo repetidas veces para nuevas líneas a medida que se agregan trozos.
En comparación con la solución de estado activo (que también parece ser cuadrática), esto no explota dado un archivo vacío, y uno busca por lectura de bloque en lugar de dos.
Comparado con el spawning 'tail', es autocontenido. (Pero 'cola' es mejor si lo tiene.)
En comparación con agarrar unos kB del extremo y con la esperanza de que sea suficiente, esto funciona para cualquier longitud de línea.
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)
utilizarlo como solicitada:
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
Editar: mapa cambiada() para itertools.imap() en la cabeza(). Editar 2: simplified reversed_blocks(). Editar 3: evitar volver a explorar la cola para nuevas líneas. Editar 4: reescribió reversed_lines() porque str.splitlines() ignora una '\ n' final, como notó BrianB (gracias).
Tenga en cuenta que en las versiones muy antiguas de Python, la concatenación de cadenas en un bucle aquí tomará un tiempo cuadrático. CPython desde al menos los últimos años evita este problema automáticamente.
duplicado exacto de http://stackoverflow.com/questions/136168/tail-a-file-with-python. –