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.
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,
"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.
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)
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()
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.