【问题标题】:Read new line with pynotify使用 pynotify 读取新行
【发布时间】:2013-04-23 17:40:49
【问题描述】:

我正在尝试显示添加到文件中的新行。 所以想象一下我有一个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()

【问题讨论】:

    标签: python file events pynotify


    【解决方案1】:

    我将解决这两个问题:

    • 如何在文件上实现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,直到处理完事件。

    另外,尽量避免 while/sleep 循环。 Inotify 添加了在收到事件后立即处理事件的能力,而不会影响资源。 while/sleep 循环的反应性较小。

    以下是pyinotify 上的Short 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_eventsEventHandler 类与方法 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()
    

    【讨论】:

    • 这太棒了!非常非常感谢!
    • 我想知道如何防止new_lines = self.file.read()read() 似乎相当昂贵,因为每次编辑文件时,您都必须阅读整个文件,这是不明智的。
    • @zizheng-wu self.file.read() 将从self.file.seek(self.position) 设置的当前文件描述符位置读取。因为我们只寻找最后一次看到的'\n'之后的位置,所以这只会读取新行,而不是整个文件。在(罕见的)数据写入时没有终止 '\n' 到文件的情况下,可以通过存储读取的数据而不是回溯到最后的 '\n' 来进一步避免一些读取。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多