PyGTK / GIO:以递归方式监视目录以进行更改

时间:2010-06-18 10:29:59

标签: python pygtk

使用以下演示代码(从GIO answer到此问题),该代码使用GIO FileMonitor监视目录以进行更改:

import gio

def directory_changed(monitor, file1, file2, evt_type):
    print "Changed:", file1, file2, evt_type

gfile = gio.File(".")
monitor = gfile.monitor_directory(gio.FILE_MONITOR_NONE, None)
monitor.connect("changed", directory_changed) 

import glib
ml = glib.MainLoop()
ml.run()

运行此代码后,我可以创建和修改子节点并收到更改通知。但是,这只适用于直接的孩子(我知道文档没有另外说明)。以下最后一个shell命令不会产生通知:

touch one
mkdir two
touch two/three

有一种简单的方法可以使其递归吗?我宁愿不手动编写寻找目录创建的东西并添加监视器,删除时删除它们等等。

预期用途是用于VCS文件浏览器扩展,以便能够在工作副本中缓存文件的状态,并在更改时单独更新它们。因此,可能会有数十到数千个(或更多)目录需要监视。我想找到工作副本的根目录并在那里添加文件监视器。

我知道pyinotify,但我正在避免它,以便在非Linux内核(如FreeBSD或其他人)下运行。据我所知,GIO FileMonitor在可用的地方使用inotify,我可以理解不强调实现以保持某种程度的抽象,但它告诉我它应该是可能的。

(如果重要,我最初在PyGTK mailing list上发布了这个。)

2 个答案:

答案 0 :(得分:2)

  

“有一种简单的方法可以做到这一点   递归?“

我不知道实现这一目标的任何“简单方法”。底层系统,例如Linux上的inotify或BSD上的kqueue,不提供自动添加递归手表的工具。我也不知道你在GIO上面想要什么库。

所以你很可能必须自己构建它。因为在某些极端情况下这可能有点戏法(例如mkdir -p foo/bar/baz)我建议看看pynotify如何实现其auto_add功能(grep通过pynotify source)并将其移植到GIO

答案 1 :(得分:1)

我不确定GIO是否允许您同时拥有多台显示器,但如果确实如此,那么您无法做出类似的事情:

import gio
import os

def directory_changed(monitor, file1, file2, evt_type):
    if os.path.isdir(file2):    #maybe this needs to be file1?
        add_monitor(file2) 
    print "Changed:", file1, file2, evt_type

def add_monitor(dir):
    gfile = gio.File(dir)
    monitor = gfile.monitor_directory(gio.FILE_MONITOR_NONE, None)
    monitor.connect("changed", directory_changed) 

add_monitor('.')

import glib
ml = glib.MainLoop()
ml.run()

*当我说没有理由的时候,这可能会成为一种资源匮乏,尽管我对GIO的知识几乎为零,我真的无法说出来。使用一些命令(os.listdir等)完全可以在Python中滚动自己。它可能看起来像这样

import time
import os

class Watcher(object):
    def __init__(self):
        self.dirs = []
        self.snapshots = {}

    def add_dir(self, dir):
        self.dirs.append(dir)

    def check_for_changes(self, dir):
        snapshot = self.snapshots.get(dir)
        curstate = os.listdir(dir)
        if not snapshot:
            self.snapshots[dir] = curstate
        else:
            if not snapshot == curstate:
                print 'Changes: ',
                for change in set(curstate).symmetric_difference(set(snapshot)):
                    if os.path.isdir(change):
                        print "isdir"
                        self.add_dir(change)
                    print change,

                self.snapshots[dir] = curstate
                print

    def mainloop(self):
        if len(self.dirs) < 1:
            print "ERROR: Please add a directory with add_dir()"
            return

        while True:
            for dir in self.dirs:
                self.check_for_changes(dir)
            time.sleep(4) # Don't want to be a resource hog

w = Watcher()
w.add_dir('.')


w.mainloop()