【问题标题】:How to get a file close event in python如何在python中获取文件关闭事件
【发布时间】:2014-04-19 19:43:04
【问题描述】:

在 windows 7 64 位机器上使用 python 2.7。

如何获取文件关闭事件:

  1. 在文件打开器的新进程中打开文件时(如记事本、写字板每次在写字板的新进程中打开文件)
  2. 在文件打开器的选项卡中打开文件时(如notepad++,它在新选项卡中打开所有文件但只存在一个notepad++运行的进程)

那么,如何在上述情况下获取文件关闭事件?是否可以通过通用代码实现上述情况?我正在处理不同的文件类型

【问题讨论】:

    标签: python windows file process file-monitoring


    【解决方案1】:

    这已被证明对于 *nix 系统来说是一项非常简单的任务,但在 Windows 上,获取文件关闭事件并不是一项简单的任务。请阅读下面按操作系统分组的常用方法的摘要。

    适用于 Linux

    在 Linux 上,可以轻松监控文件系统更改,并且非常详细。最好的工具是名为 inotify 的内核功能,并且有一个使用它的 Python 实现,称为 Pynotify。

    • Pyinotify

      Pyinotify 是一个 Python 模块,用于监控文件系统的变化。 Pinotify 依赖于名为inotify 的 Linux 内核特性(合并在内核 2.6.13 中),它是一个事件驱动的通知程序。它的通知通过三个系统调用从内核空间导出到用户空间。 Pyinotify 绑定了这些系统调用,并在它们之上提供了一个实现,提供了一种通用和抽象的方式来操作这些功能。

      Here你可以找到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

    Windows 的情况比 Linux 复杂得多。大多数库依赖于受限制的ReadDirectoryChanges API,无法检测文件关闭事件等更精细的细节。但是,还有其他方法可以检测此类事件,因此请继续阅读以了解更多信息。

    • Watcher

      注意:Watcher 的最后一次更新是在 2011 年 2 月,所以跳过这个可能是安全的。

      Watcher 是低级 C 扩展,用于在 Windows 系统上使用 ReadDirectoryChangesW API 接收文件系统更新。该软件包还包括一个高级接口,用于模拟大多数 .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()
      
    • Watchdog

      用于监控文件系统事件的 Python API 和 shell 实用程序。易于安装:$ pip install watchdog。欲了解更多信息,请访问documentation
      Windows 上的 Watchdog 依赖于 ReadDirectoryChangesW API,它带来了与 Watcher 和其他依赖相同 API 的库一样的警告。

    • Pywatch

      Linux watch 命令的 python 近似克隆。可以告诉pywatch.watcher.Watcher 类监视一组文件,并给出一组命令以在这些文件中的任何一个发生更改时运行。它只能监视文件更改事件,因为它依赖于轮询stat's st_mtime

    带有 NTFS 的 Windows 的奖励:

    • NTFS USN Journal

      NTFS USN(更新序列号)日志是 NTFS 的一项功能,它维护对卷所做的更改记录。它被列为 Bonus 的原因是因为与其他条目不同,它不是一个特定的库,而是 NTFS 系统上存在的一个功能。因此,如果您使用的是其他 Windows 文件系统(如 FAT、ReFS 等),则不适用。
      它的工作方式是系统在 USN 日志文件中记录对卷所做的所有更改,每个卷都有自己的实例。 Change Journal 中的每条记录都包含 USN、文件的名称以及有关更改内容的信息。

      这个方法对这个问题很有趣的主要原因是,与大多数其他方法不同,这个方法提供了一种检测文件关闭事件的方法,定义为USN_REASON_CLOSE强>。可以在此MSDN article 中找到包含完整事件列表的更多信息。有关 USN 日志的完整文档,请访问MSDN page

      有多种方法可以从 Python 访问 USN Journal,但唯一成熟的选项似乎是 ntfsjournal 模块。

    Windows 的“正确”方式:

    • File system filter driver

      MSDN page 所述:

      文件系统过滤器驱动程序是一个可选的驱动程序,它增加了价值 或修改文件系统的行为。文件系统过滤器驱动程序 是作为 Windows 执行程序的一部分运行的内核模式组件。 文件系统过滤器驱动程序可以过滤一个或多个 I/O 操作 文件系统或文件系统卷。根据性质 driver、filter 可以表示记录、观察、修改甚至阻止。典型的 文件系统过滤器驱动程序的应用程序包括防病毒 实用程序、加密程序和分层存储管理 系统。

      实现一个文件系统过滤驱动并不是一件容易的事,但是对于想要尝试的人来说,CodeProject上有一个很好的介绍教程。

      附:查看@ixe013's answer 了解有关此方法的更多信息。

    多平台

    • Qt's QFileSystemWatcher

      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_()
      

    【讨论】:

    • 这些 pynotify 和 inotify 用于 linux。我想要窗户。我们无法在 Windows 上安装这些库
    • 以上所有库和stackoverflow.com/questions/182197/…都是用来监控文件变化的。但我没有发现任何事件来监视文件关闭。
    • 当然有这样的事件。例如,Pynotify 实现了 close_write、close_nowrite 和 close 事件,它们完全符合您的要求。在 Windows 上,Watcher 实现 IN_CLOSE_WRITE 和 IN_CLOSE_NOWRITE 来检测此类事件。
    • 能否详细说明Watcher,或者它的文档链接
    • 很抱歉,我目前无法访问 Windows,否则我会自己尝试。文档很短,但它表明您应该创建一个 watcher.Watcher 对象并将其 flags 属性设置为所需的事件。
    【解决方案2】:

    您可以使用Pyfanotyfibutter

    我想你会发现这个链接非常有用: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()
    

    【讨论】:

    • pyinotify 适用于 linux。我想要Windows。我们无法在 Windows 上安装 pyinotify。
    【解决方案3】:

    我还没有找到在 Windows 上捕获 openclose 事件的包。正如其他人所提到的,pyinotify 是基于 Linux 的操作系统的绝佳选择。

    由于我无法观看已结束的活动,因此我选择了修改后的活动。这在很大程度上是一种“事后”类型的解决方案(即,在看到文件关闭之前我不能暂停)。但是,这出奇的好。

    我使用了watchdog 包。下面的代码来自他们的sample 实现,如果你没有在命令行上传递路径,它会监视当前目录,否则它会监视你传递的路径。

    示例调用:python test.pypython 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 event 来过滤刚刚修改的内容。

    【讨论】:

    • 我可以通过os.path.getmtime(filename) 捕捉到修改后的事件。实际上,我想在文件关闭后立即删除文件(无论是从记事本++ 选项卡还是普通记事本关闭文件)。用户可以在关闭文件之前多次修改文件。
    • @imp 我认为这里的所有答案都是错误的,因为他们试图在文件系统级别的关闭事件上回答问题,而您的评论表明您希望在应用程序级别关闭事件‽关闭文件系统级别与在应用程序中关闭文档不同,除非应用程序真正在开头打开文件并在结尾关闭它。在文本编辑器的情况下这是不太可能的。打开文档时,他们会打开文件、阅读内容并关闭它。在编辑器中关闭文档然后在文件系统级别生成 no 事件!
    【解决方案4】:

    您面临的问题不是 Python,而是 Windows。可以做到,但您必须为它编写一些非平凡的 C/C++ 代码。

    Windows 的用户空间中不存在文件打开或文件关闭用户模式通知。这就是为什么其他人建议的库没有文件关闭通知的原因。在 Windows 中,检测用户空间变化的 API 是ReadDirectoryChangesW。它会提醒你one of the following notifications

    • FILE_ACTION_ADDED 如果文件被添加到目录中。
    • FILE_ACTION_REMOVED 如果文件已从目录中删除。
    • FILE_ACTION_MODIFIED 如果文件被修改。这可能是时间戳或属性的更改。
    • FILE_ACTION_RENAMED_OLD_NAME 如果文件被重命名并且这是旧名称。
    • FILE_ACTION_RENAMED_NEW_NAME 如果文件被重命名并且这是新名称。

    再多的 Python 也无法改变 Windows 为您提供的功能。

    要获得文件关闭通知,tools like Process Monitor 在 EFS 等其他过滤器顶部附近安装 Minifilter that lives in the kernel

    要实现你想要的,你需要:

    1. 安装一个微过滤器,该微过滤器具有将事件发送回用户空间的代码。使用Microsoft's Minispy sample,稳定快速。
    2. 转换来自user 程序的代码,使其成为一个Python 扩展(minispy.pyd),它公开了一个生成事件的生成器。这是最难的部分,我会再谈。
    3. 您将不得不过滤掉事件,您不会相信空闲 Windows 机器上的 IO 量!
    4. 然后您的 Python 程序可以导入您的扩展程序并执行其操作。

    整个事情看起来像这样:

    当然,您可以在 NTFS 上使用 EFS,这只是为了表明您的微过滤器将高于一切。

    困难的部分:

    • 您的微过滤器必须由 Microsoft 信任的权威机构进行数字签名。想到了验证,但还有其他的。
    • 调试需要单独的(虚拟)机器,但您可以使您的界面易于模拟。
    • 您需要使用具有管理员权限的帐户安装微过滤器。任何用户都可以阅读事件。
    • 您将不得不自己处理多用户。许多用户只有一个微过滤器。
    • 您必须将用户程序从 MiniSpy 示例转换为 DLL,然后使用 Python 扩展进行包装。

    最后两个是最难的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-08
      • 2014-08-25
      • 2023-03-17
      • 1970-01-01
      • 2012-03-08
      • 2016-11-12
      • 2014-04-12
      相关资源
      最近更新 更多