首先安装pyinofity
,pip install pyinotify
与linux下面的inotify
事件机制类似,我们通过继承ProcessEvent
来实现对inotify
事件的重写,这里将事件名封装成process_事件名
,例如IN_CREATE
会经过Event Processor
变成process_IN_CREATE
。下面是所有的事件:
Inotify Events | Description |
---|---|
IN_CREATE | File/directory created in watched directory |
IN_OPEN | File/directory opened in watched directory |
IN_ACCESS | File accessed |
IN_ATTRIB | Attributes of file/directory changed (e.g. permissions, timestamp, etc.) |
IN_CLOSE_NOWRITE | Non-writable file/directory closed |
IN_DELETE | File/directory deleted from watched directory |
IN_DELETE_SELF | File/directory being watched deleted |
IN_IGNORED | File/directory no longer watched, deleted, or unmounted filesystem |
IN_MODIFY | File/directory modified |
IN_MOVE_SELF | File/directory moved. Must monitor destination to know destination path |
IN_MOVED_FROM | File/directory moved from one watched directory to another |
IN_MOVED_TO | Similar to IN_MOVED_FROM except for outgoing file/directory |
IN_Q_OVERFLOW | Event queue overflowed |
IN_UNMOUNT | Filesystem of watched file/directory unmounted from system |
下面将通过一个简短的例子来展示:
import os
import pyinotify
class EventProcessor(pyinotify.ProcessEvent):
_methods = ["IN_CREATE",
"IN_OPEN",
"IN_ACCESS",
"IN_ATTRIB",
"IN_CLOSE_NOWRITE",
"IN_CLOSE_WRITE",
"IN_DELETE",
"IN_DELETE_SELF",
"IN_IGNORED",
"IN_MODIFY",
"IN_MOVE_SELF",
"IN_MOVED_FROM",
"IN_MOVED_TO",
"IN_Q_OVERFLOW",
"IN_UNMOUNT",
"default"]
def process_generator(cls, method):
def _method_name(self, event):
print("Method name: process_{}()\n"
"Path name: {}\n"
"Event Name: {}\n".format(method, event.pathname, event.maskname))
_method_name.__name__ = "process_{}".format(method)
setattr(cls, _method_name.__name__, _method_name)
for method in EventProcessor._methods:
process_generator(EventProcessor, method)
watch_manager = pyinotify.WatchManager()
event_notifier = pyinotify.Notifier(watch_manager, EventProcessor())
watch_this = os.path.abspath("/home/vincent/software")
watch_manager.add_watch(watch_this, pyinotify.ALL_EVENTS)
event_notifier.loop()
这里我们可以看到,监控了一个文件夹/home/vincent/software
,当往这个文件夹中复制一份文件时,将会打印出所有对应的事件。
Method name: process_IN_CREATE()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_CREATE
Method name: process_IN_OPEN()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_OPEN
Method name: process_IN_MODIFY()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_MODIFY
Method name: process_IN_MODIFY()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_MODIFY
Method name: process_IN_MODIFY()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_MODIFY
Method name: process_IN_CLOSE_WRITE()
Path name: /home/vincent/software/Anaconda3-2021.05-Linux-x86_64.sh
Event Name: IN_CLOSE_WRITE
可以看出来,他会记录下文件操作的每一步,包括文件创建IN_CREATE
,文件打开IN_OPEN
,文件修改IN_MODIFY
,文件关闭IN_CLOSE_WRITE
上面的loop()
的方式会阻塞进程,在loop
后面的代码将不会被执行,这里有三种解决办法:
在构造notifier
时,timeout参数告诉Notifier以特定的时间间隔获取通知。
event_notifier = pyinotify.Notifier(watch_manager, EventProcessor(), timeout=10)
当使用超时时,应用程序将不会自动获得文件系统更改通知。需要在不同的时间显式调用event_notifier.process_events()
和event_notifier.read_events()
。也可以调用event_notifier.check_events()
来检查是否有事件等待处理。
可以将程序放到另一个线程中,通过ThreadedNotifier
而不是Notifier
调用,然后通过event_notifier.start()
启动
event_notifier = pyinotify.ThreadedNotifier(watch_manager, EventProcessor())
watch_this = os.path.abspath("notification_dir")
watch_manager.add_watch(watch_this, pyinotify.ALL_EVENTS)
event_notifier.start()
可以通过异步实现:
event_notifier = pyinotify.AsyncNotifier(watch_manager, EventProcessor())
然后通过调用asyncore
中的loop()
函数实现:
import asyncore
asyncore.loop()
inotify的局限性也适用于pyinotify。例如,不监视递归目录;必须运行另一个inotify实例来跟踪子目录。尽管Python提供了一个方便的inotify接口,但与C实现的inotify相比,会导致性能下降。