Estoy escribiendo un visor de archivos de registro para una aplicación web y para eso quiero paginar a través de las líneas del archivo de registro. Los elementos del archivo están basados en líneas con el elemento más nuevo en la parte inferior.
Por lo tanto, necesito un tail()
método que pueda leer n
líneas desde la parte inferior y que admita un desplazamiento. Lo que se me ocurrió se ve así:
def tail(f, n, offset=0):
"""Reads a n lines from f with an offset of offset lines."""
avg_line_length = 74
to_read = n + offset
while 1:
try:
f.seek(-(avg_line_length * to_read), 2)
except IOError:
# woops. apparently file is smaller than what we want
# to step back, go to the beginning instead
f.seek(0)
pos = f.tell()
lines = f.read().splitlines()
if len(lines) >= to_read or pos == 0:
return lines[-to_read:offset and -offset or None]
avg_line_length *= 1.3
¿Es este un enfoque razonable? ¿Cuál es la forma recomendada de seguir archivos de registro con compensaciones?
seek(0,2)
entoncestell()
), y uso ese valor para buscar en relación con el comienzo.open
comando que se utiliza para generar elf
objeto de archivo deben especificarse, ya que dependiendo sif=open(..., 'rb')
of=open(..., 'rt')
elf
debe ser procesado de manera diferenteRespuestas:
Esto puede ser más rápido que el tuyo. No hace suposiciones sobre la longitud de la línea. Retrocede el archivo un bloque a la vez hasta que se encuentra el número correcto de caracteres '\ n'.
No me gustan los supuestos engañosos sobre la longitud de la línea cuando, como cuestión práctica, nunca se pueden saber cosas así.
Generalmente, esto ubicará las últimas 20 líneas en la primera o segunda pasada a través del bucle. Si su cosa de 74 caracteres es realmente precisa, crea el tamaño de bloque 2048 y seguirá 20 líneas casi de inmediato.
Además, no quemo muchas calorías cerebrales tratando de alinear con los bloques físicos del sistema operativo. Al usar estos paquetes de E / S de alto nivel, dudo que vea alguna consecuencia de rendimiento al tratar de alinearse en los límites de bloqueo del sistema operativo. Si usa E / S de nivel inferior, es posible que vea una aceleración.
ACTUALIZAR
para Python 3.2 y versiones posteriores, siga el proceso en bytes, ya que en los archivos de texto (los que se abren sin una "b" en la cadena de modo), solo se permiten búsquedas relativas al comienzo del archivo (la excepción es buscar hasta el final del archivo) con búsqueda (0, 2)) .:
p.ej:
f = open('C:/.../../apache_logs.txt', 'rb')
fuente
io.UnsupportedOperation: can't do nonzero end-relative seeks
que puedo cambiar el desplazamiento a 0, pero eso anula el propósito de la función.Asume un sistema similar a Unix en Python 2 que puede hacer:
Para python 3 puedes hacer:
fuente
offset_total = str(n+offset)
stdin,stdout = os.popen2("tail -n "+offset_total+" "+f)
TypeErrors (cannot concatenate int+str)
Aquí está mi respuesta. Pitón pura Usando el tiempo, parece bastante rápido. Seguir 100 líneas de un archivo de registro que tiene 100,000 líneas:
Aquí está el código:
fuente
if len(lines_found) > lines:
realmente necesario? ¿Laloop
condición no lo atraparía también?os.SEEK_END
usa simplemente por claridad? Por lo que he encontrado, su valor es constante (= 2). Me preguntaba si dejarlo fuera para poder dejarlo fueraimport os
. ¡Gracias por la gran solución!os.SEEK_END
con su equivalente entero. Estaba principalmente allí para facilitar la lectura.while len(lines_found) < lines
awhile len(lines_found) <= lines
en mi copia. ¡Gracias!Si leer el archivo completo es aceptable, use una deque.
Antes de 2.6, los deques no tenían una opción maxlen, pero es bastante fácil de implementar.
Si es un requisito leer el archivo desde el final, use una búsqueda de galope (también conocido como exponencial).
fuente
pos *= 2
Parece completamente arbitrario. ¿Cuál es su significado?La respuesta anterior de S.Lott casi funciona para mí, pero termina dándome líneas parciales. Resulta que corrompe los datos en los límites de los bloques porque los datos retienen los bloques de lectura en orden inverso. Cuando se llama '' .join (datos), los bloques están en el orden incorrecto. Esto arregla eso.
fuente
El código que terminé usando. Creo que este es el mejor hasta ahora:
fuente
Solución simple y rápida con mmap:
fuente
.rfind
método para escanear hacia atrás en busca de nuevas líneas, en lugar de realizar comprobaciones de byte a nivel a nivel de Python; en CPython, reemplazando el código de nivel de Python con Las llamadas incorporadas en C generalmente ganan mucho). Para entradas más pequeñas, eldeque
con amaxlen
es más simple y probablemente igualmente rápido.Una versión compatible con Python3 aún más limpia que no se inserta, sino que agrega e invierte:
úsalo así:
fuente
Actualice la solución @papercrane a python3. Abra el archivo con
open(filename, 'rb')
y:fuente
Publicar una respuesta a instancias de los comentaristas en mi respuesta a una pregunta similar en la que se utilizó la misma técnica para mutar la última línea de un archivo, no solo para obtenerla.
Para un archivo de tamaño significativo,
mmap
es la mejor manera de hacerlo. Para mejorar lammap
respuesta existente , esta versión es portátil entre Windows y Linux, y debería ejecutarse más rápido (aunque no funcionará sin algunas modificaciones en Python de 32 bits con archivos en el rango GB, consulte la otra respuesta para obtener sugerencias sobre cómo manejar esto , y para modificar para trabajar en Python 2 ).Esto supone que el número de líneas con cola es lo suficientemente pequeño como para que pueda leerlas todas en la memoria de una vez; También puede hacer de esto una función de generador y leer manualmente una línea a la vez reemplazando la línea final con:
Por último, esta lectura en modo binario (necesaria para usar
mmap
) por lo que dastr
líneas (Py2) ybytes
líneas (Py3); si deseaunicode
(Py2) ostr
(Py3), el enfoque iterativo podría modificarse para decodificarlo y / o corregir nuevas líneas:Nota: Escribí todo esto en una máquina donde no tengo acceso a Python para probar. Avísame si escribí algo; esto fue lo suficientemente similar a mi otra respuesta que yo creo que debería funcionar, pero los ajustes (por ejemplo, manejo de un
offset
) podrían dar lugar a errores sutiles. Por favor, avíseme en los comentarios si hay algún error.fuente
Encontré el Popen anterior para ser la mejor solución. Es rápido y sucio y funciona Para Python 2.6 en la máquina Unix, utilicé lo siguiente
soutput tendrá contendrá las últimas n líneas del código. para iterar a través de la línea sur por línea:
fuente
basado en la respuesta más votada de S.Lott (25 de septiembre de 08 a las 21:43), pero corregido para archivos pequeños.
Espero que esto sea útil.
fuente
Hay algunas implementaciones existentes de tail en pypi que puedes instalar usando pip:
Dependiendo de su situación, puede haber ventajas al usar una de estas herramientas existentes.
fuente
tailhead
,tailer
pero no funcionaron. También lo intentémtFileUtil
. Inicialmente arrojó un error porque lasprint
declaraciones no tenían paréntesis (estoy en Python 3.6). Agregué esosreverse.py
y los mensajes de error desaparecieron, pero cuando mi script llama al módulo (mtFileUtil.tail(open(logfile_path), 5)
), no imprime nada.Sencillo :
fuente
Para una mayor eficiencia con archivos muy grandes (comunes en situaciones de archivos de registro en los que es posible que desee utilizar la cola), generalmente desea evitar leer el archivo completo (incluso si lo hace sin leer todo el archivo en la memoria de una vez) Sin embargo, sí lo hace necesita de alguna manera resolver el desplazamiento en líneas en lugar de caracteres. Una posibilidad es leer hacia atrás con seek () char by char, pero esto es muy lento. En cambio, es mejor procesar en bloques más grandes.
Tengo una función de utilidad que escribí hace un tiempo para leer archivos al revés que se pueden usar aquí.
[Editar] Se agregó una versión más específica (evita la necesidad de revertir dos veces)
fuente
puede ir al final de su archivo con f.seek (0, 2) y luego leer las líneas una por una con el siguiente reemplazo para readline ():
fuente
Basado en la respuesta de Eyecue (10 de junio de 2010 a las 21:28): esta clase agrega el método head () y tail () para archivar el objeto.
Uso:
fuente
Varias de estas soluciones tienen problemas si el archivo no termina en \ n o para garantizar que se lea la primera línea completa.
fuente
Aquí hay una implementación bastante simple:
fuente
f.seek
? ¿Por qué no antes de lawith open
? Además, ¿porexcept
qué haces unf.readlines()
??Hay un módulo muy útil que puede hacer esto:
fuente
Otra solución
si su archivo txt se ve así: ratón serpiente gato lagarto lobo perro
podría revertir este archivo simplemente usando la indexación de matriz en python '' '
resultado: perro lobo gato lagarto
fuente
La forma más simple es usar
deque
:fuente
Tuve que leer un valor específico de la última línea de un archivo, y me topé con este hilo. En lugar de reinventar la rueda en Python, terminé con un pequeño script de shell, guardado como / usr / local / bin / get_last_netp:
Y en el programa Python:
fuente
No es el primer ejemplo que usa un deque, sino uno más simple. Este es general: funciona en cualquier objeto iterable, no solo en un archivo.
fuente
fuente
fuente
fuente
fuente
Actualización para la respuesta dada por A.Coady
Funciona con python 3 .
Esto usa la búsqueda exponencial y almacenará solo las
N
líneas desde atrás y es muy eficiente.fuente
Pensándolo bien, esto es probablemente tan rápido como cualquier cosa aquí.
Es mucho mas simple. Y parece ir a buen ritmo.
fuente