Прочитать новую строку с pynotify

Я пытаюсь отобразить новую строку, которая была добавлена ​​в файл. Итак, представьте, что у меня есть sample_file.txt:

 1. line 1
 2. line 2
 3. line 3

Я хочу проверить, получил ли этот файл новую строку, и затем отобразить эту строку (без повторной печати всего файла)

#!/usr/bin/python

import os
import pyinotify
from datetime import datetime
import time

PATH = os.path.join(os.path.expanduser('~/'), 'sample_file.txt')

m = pyinotify.WatchManager()
m.add_watch(PATH, pyinotify.ALL_EVENTS, rec=True)
notifier = pyinotify.Notifier(m, pyinotify.ProcessEvent(), 0,  0, 100)

f = open(PATH)
for line in f.readlines():
    print line

while True:
    time.sleep(5)
    try:
        if notifier.check_events():
            # RIGHT HERE:
            # HOW TO DO SOMETHING LIKE
            # f.last() ???
            print f.next()
        else:
            print 'waiting for a line....'
    except KeyboardInterrupt:
        notifier.stop()
        break

Я думал о том, чтобы прочитать все строки где-то перед циклом while, а затем вывести следующую строку, но что-то не так в моем коде, и он проверяет f.next() сразу после того, как дело доходит до петли.

1 ответ

Решение

Я рассмотрю два вопроса:

  • как реализовать tail в файле,
  • и как использовать pyinotify модуль.

Хвост по файлу

В вашем коде вам необходимо:

  • попробуйте прочитать как можно больше полных строк, используя read или же readlines,
  • перемотайте файл до начала последней незавершенной строки, пока вы не сможете распечатать его, используя seek,

Это переводит, например, в:

f = open(PATH)
for line in f.readlines():
    print line[:-1]

while True:
    time.sleep(5)
    try:
        line_start = f.tell()
        new_lines = f.read()
        last_n = new_lines.rfind('\n')
        if last_n >= 0:
            # We got at least one full line
            line_start += last_n + 1
            print new_lines[:last_n]
        else:
            # No complete line yet
            print 'no line'
        f.seek(line_start)
    except KeyboardInterrupt:
        notifier.stop()
        break

Вы можете найти больше примеров здесь, хотя некоторые не обращаются к дополнениям к файлу, которые не заканчиваются новой строкой:

И некоторые альтернативы здесь Как я могу подключить файл журнала в Python?

Петля пиинотификации

Вы также должны переместить свой код внутрь pyinotifyобработчики событий, как описано в документации.

check_events возвращается True если есть события, которые нужно обработать, но он на самом деле не обрабатывает события, поэтому сам по себе он всегда вернет True пока события не были обработаны.

Кроме того, постарайтесь избежать while/sleep петли. Inotify добавляет возможность обрабатывать событие как можно быстрее, без ущерба для ресурсов. while/sleep петля будет менее реактивной.

Ниже приведены два первых метода из краткого учебника по pyinotify,

1. Мониторинг бесконечно

Это предпочтительный метод, если у вас нет другого цикла событий, так как он будет наиболее реактивным:

PATH = os.path.join(os.path.expanduser('~/'), 'experiments', 'testfile')

class EventHandler(pyinotify.ProcessEvent):
    def __init__(self, *args, **kwargs):
        super(EventHandler, self).__init__(*args, **kwargs)
        self.file = open(PATH)
        self.position = 0
        self.print_lines()

    def process_IN_MODIFY(self, event):
        print 'event received'
        self.print_lines()

    def print_lines(self):
        new_lines = self.file.read()
        last_n = new_lines.rfind('\n')
        if last_n >= 0:
            self.position += last_n + 1
            print new_lines[:last_n]
        else:
            print 'no line'
        self.file.seek(self.position)

wm = pyinotify.WatchManager()
handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler)
wm.add_watch(PATH, pyinotify.IN_MODIFY, rec=True)
notifier.loop()

2. Периодический мониторинг

Если у вас уже есть цикл обработки, то это просто вопрос вызова process_events периодически. EventHandler класс такой же, как в методе 1, но теперь вместо вызова notifier.loop() мы добавляем небольшой таймаут к уведомителю и реализуем наш собственный цикл обработки событий.

...

wm = pyinotify.WatchManager()
handler = EventHandler()
notifier = pyinotify.Notifier(wm, handler, timeout=10)
wm.add_watch(PATH, pyinotify.IN_MODIFY, rec=True)

while True:
    # Do something unrelated to pyinotify
    time.sleep(5)

    notifier.process_events()
    #loop in case more events appear while we are processing
    while notifier.check_events():
        notifier.read_events()
        notifier.process_events()
Другие вопросы по тегам