Lectura de un archivo que se actualiza frecuentemente

Actualmente estoy escribiendo un programa en python en un sistema Linux. El objetivo es leer un archivo de registro y ejecutar un comando de bash en la búsqueda de una cadena en particular. El archivo de registro está siendo constantemente por escrito por otro programa. Mi pregunta es:

Si puedo abrir el archivo utilizando el método open() mi archivo de Python objeto de ser actualizado a medida que los archivos se escriben en el otro programa o tengo que volver a abrir el archivo en intervalos de tiempo?

Gracias

Jim

ACTUALIZACIÓN:
Gracias por las respuestas hasta ahora. Tal vez yo debería haber mencionado que el archivo está siendo escrita por un Java EE aplicación, de modo que no tengo control sobre cuando los datos se escriben en ella. He actualmente tengo un programa que vuelve a abrir el archivo cada 10 segundos e intenta leer desde la posición de byte en el archivo de la última lectura de hasta. Por el momento sólo se imprime la cadena que se devuelve. Tenía la esperanza de que el archivo no necesita ser abierto de nuevo, pero el comando de lectura, de alguna manera tienen acceso a los datos se escriben en el archivo por la aplicación Java.

#!/usr/bin/python
import time

fileBytePos = 0
while True:
    inFile = open('./server.log','r')
    inFile.seek(fileBytePos)
    data = inFile.read()
    print data
    fileBytePos = inFile.tell()
    print fileBytePos
    inFile.close()
    time.sleep(10)

Gracias por los consejos sobre pyinotify y generadores. Voy a echar un vistazo a estos para una mejor solución.

InformationsquelleAutor JimS | 2011-03-24

6 Kommentare

  1. 87

    Yo recomendaría mirar a David Beazley del Generador de Trucos para Python, especialmente Parte 5: Procesamiento Infinito de Datos. Se ocupará de la Python equivalente de un tail -f logfile comando en tiempo real.

    # follow.py
    #
    # Follow a file like tail -f.
    
    import time
    def follow(thefile):
        thefile.seek(0,2)
        while True:
            line = thefile.readline()
            if not line:
                time.sleep(0.1)
                continue
            yield line
    
    if __name__ == '__main__':
        logfile = open("run/foo/access-log","r")
        loglines = follow(logfile)
        for line in loglines:
            print line,
    • Me gustaría upvote si la respuesta contiene un código de ejemplo en términos de la OP del código.
    • añadido código de ejemplo de David Beazley del sitio
    • Esta respuesta en mi humilde opinión es un error, si el escritor escribe una línea en dos trozos separados de la readline devolverá el doble. Pero en realidad sólo quiere regresar una sola línea.
    • No puede conseguir que funcione. Tal vez diferentes en Python 3?
    • Rotación de registros de terminar encima de conseguir el archivo cambia de nombre, y, a continuación, este código va a esperar para siempre en el antiguo archivo de registro. Tuve este problema y resuelto de esta manera, que también se resuelve el time.sleep(0.1) problema stackoverflow.com/a/44411621/277267
    • hace este trabajo asíncrono? quiero decir, no bloquear el proceso que se ejecuta desde?
    • He probado esta aplicación con asyncio y mi generador era demasiado rápido y consiguió trozos 90% del tiempo en lugar de toda la línea 🙁
    • Cómo utilizar esta misma función en un HttpStreaminResponse, quiero mostrar la misma en el navegador
    • ¿qué thefile.seek(0,2) hacer?
    • es el desplazamiento, 2 significa buscar relativa a la del archivo final.

  2. 17

    «Una sesión interactiva vale más que 1000 palabras»

    >>> f1 = open("bla.txt", "wt")
    >>> f2 = open("bla.txt", "rt")
    >>> f1.write("bleh")
    >>> f2.read()
    ''
    >>> f1.flush()
    >>> f2.read()
    'bleh'
    >>> f1.write("blargh")
    >>> f1.flush()
    >>> f2.read()
    'blargh'

    En otras palabras – sí, un solo «abrir» va a hacer.

    • Esto es interesante saber!
  3. 5

    Aquí es una versión ligeramente modificada de Jeff Bauer respuesta que es resistente al truncamiento de archivo. Muy útil si su archivo está siendo procesado por logrotate.

    import os
    import time
    
    def follow(name):
        current = open(name, "r")
        curino = os.fstat(current.fileno()).st_ino
        while True:
            while True:
                line = current.readline()
                if not line:
                    break
                yield line
    
            try:
                if os.stat(name).st_ino != curino:
                    new = open(name, "r")
                    current.close()
                    current = new
                    curino = os.fstat(current.fileno()).st_ino
                    continue
            except IOError:
                pass
            time.sleep(1)
    
    
    if __name__ == '__main__':
        fname = "test.log"
        for l in follow(fname):
            print "LINE: {}".format(l)
    • Asusta ver while True: while True:
  4. 3

    Ya que usted está apuntando a un sistema Linux, puede utilizar pyinotify para que le notifique cuando los cambios en el archivo.

    También hay este truco, que puede funcionar bien para usted. Utiliza file.seek a hacer lo que tail -f hace.

  5. 1

    No soy experto, pero me parece que usted tendrá que utilizar algún tipo de patrón observer pasivamente ver el archivo y, a continuación, disparar un evento que vuelve a abrir el archivo cuando se produce un cambio. Como para implementar esto, no tengo idea.

    No creo que open() se abrirá el archivo en tiempo real, como usted sugiere.

  6. 1

    Si tiene el código de lectura del fichero que se ejecuta en un bucle while:

    f = open('/tmp/workfile', 'r')
    while(1):
        line = f.readline()
        if line.find("ONE") != -1:
            print "Got it"

    y escribir en ese mismo archivo ( en modo append ) desde otro programa. Tan pronto como «UNO», se añade en el archivo de impresión. Usted puede tomar cualquier acción que usted desea tomar. En resumen, usted no tiene que volver a abrir el archivo en intervalos regulares.

    >>> f = open('/tmp/workfile', 'a')
    >>> f.write("One\n")
    >>> f.close()
    >>> f = open('/tmp/workfile', 'a')
    >>> f.write("ONE\n")
    >>> f.close()
    • Esta respuesta también es incorrecto, la escritura podría conseguir dividido en ‘ON’ y ‘E’ \n’ que daría lugar a una línea donde ni los partidos.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea