Чтение из часто обновляемого файла - PullRequest
43 голосов
/ 24 марта 2011

В настоящее время я пишу программу на python для системы Linux.Цель состоит в том, чтобы прочитать файл журнала и выполнить команду bash после нахождения конкретной строки.Файл журнала постоянно записывается другой программой.Мой вопрос:

Если я открою файл с помощью метода open (), будет ли обновлен мой объект Python, когда фактический файл будет записан другой программой, или мне придется повторно открывать файл через определенные интервалы времени?

Спасибо

Джим

ОБНОВЛЕНИЕ: Спасибо за ответы до сих пор.Возможно, я должен был упомянуть, что файл записывается приложением Java EE, поэтому я не могу контролировать, когда в него записываются данные.В настоящее время у меня есть программа, которая повторно открывает файл каждые 10 секунд и пытается прочитать с позиции байта в файле, до которого он последний раз читал.На данный момент он просто распечатывает возвращенную строку.Я надеялся, что файл не нужно открывать повторно, но команда чтения каким-то образом будет иметь доступ к данным, записанным в файл приложением 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)

Спасибо за советы по pyinotify и генераторам.Я собираюсь взглянуть на них для лучшего решения.

Ответы [ 6 ]

80 голосов
/ 24 марта 2011

Я бы порекомендовал посмотреть Генераторские хитрости Дэвида Бизли для Python , особенно Часть 5: Обработка бесконечных данных Он будет обрабатывать Python-эквивалент команды tail -f logfile в режиме реального времени.

# 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,
17 голосов
/ 24 марта 2011

«Интерактивный сеанс стоит 1000 слов»

>>> 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'

Другими словами - да, подойдет только один «открытый».

5 голосов
/ 29 августа 2016

Вот слегка измененная версия ответа Джефф Бауэр , который устойчив к усечению файла.Очень полезно, если ваш файл обрабатывается 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)
3 голосов
/ 24 марта 2011

Поскольку вы ориентируетесь на систему Linux, вы можете использовать pyinotify , чтобы уведомлять вас об изменении файла.

Есть также этот трюк, который может хорошо работать для вас. Он использует file.seek, чтобы делать то, что делает tail -f.

1 голос
/ 24 марта 2011

Если у вас есть код, читающий файл, работающий в цикле while:

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

, и вы пишете в тот же файл (в режиме добавления) из другой программы.Как только в файл добавлено «ОДИН», вы получите распечатку.Вы можете предпринять любое действие, которое хотите.Короче говоря, вам не нужно регулярно открывать файл.

>>> f = open('/tmp/workfile', 'a')
>>> f.write("One\n")
>>> f.close()
>>> f = open('/tmp/workfile', 'a')
>>> f.write("ONE\n")
>>> f.close()
1 голос
/ 24 марта 2011

Я не эксперт здесь, но я думаю, что вам придется использовать какой-то шаблон наблюдателя для пассивного просмотра файла, а затем запустить событие, которое открывает файл снова, когда происходит изменение. Что касается того, как на самом деле реализовать это, я понятия не имею.

Я не думаю, что open () откроет файл в реальном времени, как вы предлагаете.

...