web-dev-qa-db-fra.com

Lecture à partir d'un fichier fréquemment mis à jour

J'écris actuellement un programme en python sur un système Linux. L'objectif est de lire un fichier journal et d'exécuter une commande bash lors de la recherche d'une chaîne particulière. Le fichier journal est constamment écrit dans par un autre programme. Ma question est:

Si j'ouvre le fichier à l'aide de la méthode open (), mon objet fichier Python sera-t-il mis à jour à mesure que le fichier réel est écrit par l'autre programme ou devrai-je rouvrir le fichier à intervalles réguliers?

Merci

Jim

MISE À JOUR: Merci pour les réponses jusqu'à présent. J'aurais peut-être dû mentionner que le fichier est écrit par une application Java EE, donc je n'ai aucun contrôle sur le moment où les données y sont écrites. J'ai actuellement un programme qui rouvre le fichier toutes les 10 secondes et essaie de lire à partir de la position d'octet dans le dernier fichier lu. Pour le moment, il imprime simplement la chaîne renvoyée. J'espérais que le fichier n'avait pas besoin d'être rouvert mais la commande de lecture le ferait avoir en quelque sorte accès aux données écrites dans le fichier par l'application 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)

Merci pour les conseils sur pyinotify et les générateurs. Je vais y jeter un œil pour une meilleure solution.

43
JimS

Je recommanderais de regarder Astuces de générateur pour Python de David Beazley, en particulier Partie 5: Traitement de données infinies . Il gérera l'équivalent Python d'un tail -f logfile commande en temps réel.

# 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 __== '__main__':
    logfile = open("run/foo/access-log","r")
    loglines = follow(logfile)
    for line in loglines:
        print line,
83
Jeff Bauer

"Une session interactive vaut 1000 mots"

>>> 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 d'autres termes - oui, un seul "ouvert" fera l'affaire.

17
jsbueno

Voici une version légèrement modifiée de la réponse Jeff Bauer qui résiste à la troncature des fichiers. Très utile si votre fichier est en cours de traitement par 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 __== '__main__':
    fname = "test.log"
    for l in follow(fname):
        print "LINE: {}".format(l)
5
Andrew Druchenko

Puisque vous ciblez un système Linux, vous pouvez utiliser pyinotify pour vous avertir lorsque le fichier change.

Il y a aussi this truc, qui peut bien fonctionner pour vous. Il utilise file.seek pour faire quoi tail -f Est-ce que.

3
nmichaels

Si le code de lecture du fichier s'exécute dans une boucle while:

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

et vous écrivez dans ce même fichier (en mode ajout) à partir d'un autre programme. Dès que "ONE" est ajouté dans le fichier, vous obtenez l'impression. Vous pouvez prendre toutes les mesures que vous souhaitez prendre. En bref, vous n'avez pas besoin de rouvrir le fichier à intervalles réguliers.

>>> f = open('/tmp/workfile', 'a')
>>> f.write("One\n")
>>> f.close()
>>> f = open('/tmp/workfile', 'a')
>>> f.write("ONE\n")
>>> f.close()
1
w00t

Je ne suis pas un expert ici, mais je pense que vous devrez utiliser une sorte de modèle d'observateur pour regarder passivement le fichier, puis déclencher un événement qui rouvrira le fichier lorsqu'un changement se produit. Quant à la façon de réellement mettre en œuvre cela, je n'ai aucune idée.

Je ne pense pas que open () ouvrira le fichier en temps réel comme vous le suggérez.

1
Adam Pointer