用pynotify阅读新行

时间:2013-04-23 17:40:50

标签: python file events 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

我想的是在循环之前读取所有行,然后打印下一行,但是我的代码出错了,它在循环后立即检查f.next()。 / p>

1 个答案:

答案 0 :(得分:4)

我将解决这两个问题:

  • 如何在文件上实现tail
  • 以及如何使用pyinotify模块。

在文件上尾巴

在您的代码中,您需要:

  • 尽量使用readreadlines
  • 阅读尽可能多的完整行
  • 将文件倒回到最后一个不完整行的开头,直到您可以使用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

你可以在这里找到更多的例子,虽然有些例子没有解决文件中没有以换行符结尾的内容:

这里有一些替代方案How can I tail a log file in Python?

Pyinotify循环

您还应该按照文档中的说明在pyinotify的事件处理程序中移动代码。

如果有要处理的事件,

check_events会返回True,但它实际上并不会处理事件,所以在事件处理完毕之前,它总是会返回True。 / p>

另外,请尝试避免while / sleep循环。 Inotify增加了在接收事件时处理事件的功能,而不会影响资源。 while / sleep循环的反应性会降低。

以下是pyinotifyShort Tutorial的两个第一种方法。

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()