在 Windows 7 64 位机器上使用 python 2.7。
如何获取文件关闭事件:
- 当文件在文件打开器的新进程中打开时(如记事本,写字板,每次在写字板的新进程中打开文件)
- 当文件在文件打开器的选项卡中打开时(如记事本++,它在新选项卡中打开所有文件但只存在一个记事本++运行的进程)
那么,如何在上述情况下获取文件关闭事件?是否可以通过通用代码实现上述情况?我正在处理不同的文件类型
在 Windows 7 64 位机器上使用 python 2.7。
如何获取文件关闭事件:
那么,如何在上述情况下获取文件关闭事件?是否可以通过通用代码实现上述情况?我正在处理不同的文件类型
对于 *nix 系统,这已被证明是一项非常容易的任务,但在 Windows 上,获取文件关闭事件并不是一项简单的任务。请阅读下面按操作系统分组的常用方法的摘要。
在 Linux 上,可以很容易地监控文件系统的变化,而且非常详细。最好的工具是名为 的内核功能inotify
,并且有一个使用它的 Python 实现,称为 Pynotify。
Pyinotify
是一个用于监视文件系统更改的 Python 模块。Pinotify 依赖于一个名为 的 Linux 内核特性(在内核 2.6.13 中合并)inotify
,它是一个事件驱动的通知程序。它的通知通过三个系统调用从内核空间导出到用户空间。Pyinotify
绑定这些系统调用并在它们之上提供一个实现,提供一种通用和抽象的方式来操作这些功能。
在这里您可以找到可以使用 监控的事件列表Pynotify
。
示例用法:
导入 pyinotify
class EventHandler(pyinotify.ProcessEvent):
def process_IN_CLOSE_NOWRITE(self, event):
print "File was closed without writing: " + event.pathname
def process_IN_CLOSE_WRITE(self, event):
print "File was closed with writing: " + event.pathname
def watch(filename):
wm = pyinotify.WatchManager()
mask = pyinotify.IN_CLOSE_NOWRITE | pyinotify.IN_CLOSE_WRITE
wm.add_watch(filename, mask)
eh = EventHandler()
notifier = pyinotify.Notifier(wm, eh)
notifier.loop()
if __name__ == '__main__':
watch('/path/to/file')
Windows 的情况比 Linux 复杂得多。大多数库依赖于ReadDirectoryChanges
受限制的 API,无法检测到文件关闭事件等更精细的细节。但是,还有其他方法可以检测此类事件,因此请继续阅读以了解更多信息。
注意: Watcher 最后一次更新是在 2011 年 2 月,所以跳过这个可能是安全的。
Watcher
是用于在 Windows 系统上使用 APIC
接收文件系统更新的低级扩展。ReadDirectoryChangesW
该软件包还包括一个高级接口,用于模拟大多数 .NET FileSystemWatcher
API。
最接近使用 Watcher 检测文件关闭事件的方法是监视FILE_NOTIFY_CHANGE_LAST_WRITE
和/或FILE_NOTIFY_CHANGE_LAST_ACCESS
事件。
示例用法:
import watcher
w = watcher.Watcher(dir, callback)
w.flags = watcher.FILE_NOTIFY_CHANGE_LAST_WRITE
w.start()
用于监视文件系统事件的 Python API 和 shell 实用程序。易于安装:$ pip install watchdog
. 有关更多信息,请访问文档。
Windows 上的 Watchdog 依赖于ReadDirectoryChangesW
API,这带来了与 Watcher 和其他依赖于相同 API 的库一样的警告。
watch
Linux命令的 python 近似克隆。pywatch.watcher.Watcher
可以告诉该类监视一组文件,并给出一组命令以在任何这些文件发生更改时运行。它只能监视文件更改事件,因为它依赖于轮询统计信息的 st_mtime。
NTFS USN(更新序列号)日志是 NTFS 的一项功能,它维护对卷所做更改的记录。它被列为奖励的原因是因为与其他条目不同,它不是一个特定的库,而是 NTFS 系统上存在的一个特性。因此,如果您使用的是其他 Windows 文件系统(如 FAT、ReFS 等),则不适用。
它的工作方式是系统在 USN 日志文件中记录对卷所做的所有更改,每个卷都有自己的实例。Change Journal 中的每条记录都包含 USN、文件的名称以及有关更改内容的信息。
这个方法对这个问题感兴趣的主要原因是,与大多数其他方法不同,这个方法提供了一种检测文件关闭事件的方法,定义为USN_REASON_CLOSE。可以在此MSDN 文章中找到包含完整事件列表的更多信息。有关 USN 日记的完整文档,请访问此MSDN 页面。
从 Python 访问 USN Journal 有多种方法,但唯一成熟的选项似乎是ntfsjournal模块。
如MSDN 页面所述:
文件系统过滤器驱动程序是一个可选的驱动程序,可以为文件系统增加价值或修改其行为。文件系统过滤器驱动程序是作为 Windows 执行程序的一部分运行的内核模式组件。文件系统过滤器驱动程序可以过滤一个或多个文件系统或文件系统卷的 I/O 操作。根据驱动程序的性质,过滤器可以表示记录、观察、修改甚至阻止。文件系统过滤驱动程序的典型应用包括防病毒实用程序、加密程序和分层存储管理系统。
实现一个文件系统过滤驱动并不是一件容易的事,但是对于想要尝试的人来说,CodeProject上有一个很好的介绍教程。
PS 检查 @ixe013 的答案以获取有关此方法的一些附加信息。
该类QFileSystemWatcher
提供了一个用于监视文件和目录以进行修改的接口。这个类是在Qt 4.2
.
不幸的是,它的功能相当有限,因为它只能检测文件何时被修改、重命名或删除,以及何时将新文件添加到目录中。
示例用法:
import sys
from PyQt4 import QtCore
def directory_changed(path):
print('Directory Changed: %s' % path)
def file_changed(path):
print('File Changed: %s' % path)
app = QtCore.QCoreApplication(sys.argv)
paths = ['/path/to/file']
fs_watcher = QtCore.QFileSystemWatcher(paths)
fs_watcher.directoryChanged.connect(directory_changed)
fs_watcher.fileChanged.connect(file_changed)
app.exec_()
您面临的问题不是 Python,而是 Windows。它可以完成,但您必须为它编写一些非平凡的 C/C++ 代码。
Windows 的用户空间中不存在文件打开或文件关闭用户模式通知。这就是为什么其他人建议的库没有文件关闭通知的原因。在 Windows 中,检测用户空间变化的 API 是ReadDirectoryChangesW。它会提醒您以下通知之一:
FILE_ACTION_ADDED
如果文件被添加到目录中。FILE_ACTION_REMOVED
如果从目录中删除了文件。FILE_ACTION_MODIFIED
如果文件被修改。这可以是时间戳或属性的更改。FILE_ACTION_RENAMED_OLD_NAME
如果文件被重命名并且这是旧名称。FILE_ACTION_RENAMED_NEW_NAME
如果文件被重命名并且这是新名称。再多的 Python 也无法改变 Windows 为您提供的功能。
为了获得文件关闭通知,Process Monitor 之类的工具安装了一个Minifilter,它位于内核中,靠近 EFS 等其他过滤器的顶部。
为了实现你想要的,你需要:
user
程序中的代码,使其成为 Python 扩展 ( minispy.pyd
),公开生成事件的生成器。这是困难的部分,我会回到那个。整个事情看起来像这样:
当然,您可以在 NTFS 上使用 EFS,这只是为了表明您的微过滤器将高于一切。
困难的部分:
最后两个是最难的。
我还没有找到在 Windows 上捕获open
和close
事件的包。正如其他人所提到的,pyinotify是基于 Linux 的操作系统的绝佳选择。
由于我无法观看已结束的活动,因此我选择了修改后的活动。这在很大程度上是一种“事后”类型的解决方案(即,在看到文件关闭之前我不能暂停)。但是,这出奇的好。
我已经使用了看门狗包。下面的代码来自他们的示例实现,如果您不在命令行上传递路径,它会监视当前目录,否则它会监视您传递的路径。
示例调用: python test.py
或python test.py C:\Users\Administrator\Desktop
import sys
import time
import logging
from watchdog.observers import Observer
from watchdog.events import LoggingEventHandler
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
path = sys.argv[1] if len(sys.argv) > 1 else '.'
event_handler = LoggingEventHandler()
observer = Observer()
observer.schedule(event_handler, path, recursive=True)
observer.start()
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
此代码将向您显示何时创建、修改、删除或重命名/移动文件。您可以通过观察on_modified
事件来过滤刚刚修改的内容。
您可以使用Pyfanotyfi或黄油。
我想你会发现这个链接非常有用:Linux file system events with C, Python and Ruby
在那里你会找到一个关于做你想做的事的例子(使用pyinotify)这是代码:
import pyinotify
DIR_TO_WATCH="/tmp/notify-dir"
FILE_TO_WATCH="/tmp/notify-dir/notify-file.txt"
wm = pyinotify.WatchManager()
dir_events = pyinotify.IN_DELETE | pyinotify.IN_CREATE
file_events = pyinotify.IN_OPEN | pyinotify.IN_CLOSE_WRITE | pyinotify.IN_CLOSE_NOWRITE
class EventHandler(pyinotify.ProcessEvent):
def process_IN_DELETE(self, event):
print("File %s was deleted" % event.pathname) #python 3 style print function
def process_IN_CREATE(self, event):
print("File %s was created" % event.pathname)
def process_IN_OPEN(self, event):
print("File %s was opened" % event.pathname)
def process_IN_CLOSE_WRITE(self, event):
print("File %s was closed after writing" % event.pathname)
def process_IN_CLOSE_NOWRITE(self, event):
print("File %s was closed after reading" % event.pathname)
event_handler = EventHandler()
notifier = pyinotify.Notifier(wm, event_handler)
wm.add_watch(DIR_TO_WATCH, dir_events)
wm.add_watch(FILE_TO_WATCH, file_events)
notifier.loop()