Inspired by another snippet here that watches a directory... Here is a directory watcher that only works on Linux, as it uses the asyncronous directory notify feature. It will generate a SIGIO on directory change. You should define a signal handler that calls this back (actaully, calls the instance).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | ################################################################
# DirectoryNotifier encapslates the code required for watching directory entry
# contents. Subclass this and override the entry_added() and entry_removed()
# methods. then, instantiate it with a directory name, and register it with the
# sighandler instance. NOTE: this only works with Python 2.2 or greater on Linux.
# Example:
# dn = DirectoryNotifier(os.environ["HOME"])
# manager.register(dn)
class DirectoryNotifier:
def __init__(self, dirname):
if not os.path.isdir(dirname):
raise RuntimeError, "you can only watch a directory."
self.dirname = dirname
self.fd = os.open(dirname, 0)
self.currentcontents = os.listdir(dirname)
self.oldsig = fcntl.fcntl(self.fd, fcntl.F_GETSIG)
fcntl.fcntl(self.fd, fcntl.F_SETSIG, 0)
fcntl.fcntl(self.fd, fcntl.F_NOTIFY, fcntl.DN_DELETE|fcntl.DN_CREATE|fcntl.DN_MULTISHOT)
def __del__(self):
# fcntl.fcntl(self.fd, fcntl.F_SETSIG, self.oldsig)
os.close(self.fd)
def __str__(self):
return "%s watching %s" % (self.__class__.__name__, self.dirname)
# there are lots of race conditions here, but we'll live with that for now.
def __call__(self, frame):
newcontents = os.listdir(self.dirname)
if len(newcontents) > len(self.currentcontents):
new = filter(lambda item: item not in self.currentcontents, newcontents)
self.entry_added(new)
elif len(newcontents) < len(self.currentcontents):
rem = filter(lambda item: item not in newcontents, self.currentcontents)
self.entry_removed(rem)
else:
self.no_change()
self.currentcontents = newcontents
# override these in a subclass
def entry_added(self, added):
print added, "added to", self.dirname
def entry_removed(self, removed):
print removed, "removed from", self.dirname
def no_change(self):
print "No change in", self.dirname
|
Tags: sysadmin
To use this recipe ...
These are needed by the class.
Next, the "sighandler" he mentions is here: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/217830
Also note that the argument passed to the object when a directory's contents change is a list, not a single filename. If you want to perform some action on each file, you will need to iterate over the argument "added" or "removed".