I'm trying to display a new line that was added to the file.
So imagine that I have a sample_file.txt
:
1. line 1
2. line 2
3. line 3
I want to check if this file got a new line, and than display that line (without printing all the file again)
#!/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
What I was thinking is to read all the lines somewhere before while loop, and than print the next line, but something wrong in my code, and it checks for f.next()
right after it comes to the loop.
I'll address the two issues:
tail
on a file,pyinotify
module.In your code, you need to:
read
or readlines
,seek
.This translates for example into:
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
You can find more examples here, although some do not address additions to the file which do not end with a newline:
And some alternatives here How can I tail a log file in Python?
You should also move your code inside pyinotify
's event handlers as explained in the documentation.
check_events
returns True
if there are events to be processed, but it does not actually process the events, so by itself it will always return True
until events have been processed.
Also, try and avoid while
/sleep
loops. Inotify adds the capability to handle an event as soons as it is received, without compromising resources. A while
/sleep
loop will be less reactive.
Below are the two first methods form the Short Tutorial on pyinotify
.
This is the preferred method if you have no other event loop, as it will be the most reactive:
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()
If you already have a processing loop, then it's just a matter of calling process_events
periodically. The EventHandler
class is the same as in method 1, but now instead of calling notifier.loop()
we add a small timeout to the notifier, and implement our own event 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()