ReadDirectoryChangesW阻止删除监视目录

时间:2011-07-26 10:19:53

标签: python winapi readdirectorychangesw

我正在尝试使用ReadDirectoryChangesW API在python上观看用于创建/删除/重命名更改的目录。这是我的代码,它运行正常:

results = win32file.ReadDirectoryChangesW(self.hDir, 8192, True, self.type, None,
                                           None)
for action, file in results:
    full_filename = os.path.join (self.source_path, file)
    if   action == 1:                                    # Created
        self.fileCreated(full_filename)
    elif action == 2:                                    # Deleted
        self.fileDeleted(full_filename)
    elif action == 3:                                    # Updated
        self.fileUpdated(full_filename)
    elif action == 4:                                    # Renamed from something
        renamed_file = full_filename
    elif action == 5:                                    # Renamed to something
        self.fileRenamed(renamed_file, full_filename)

但是,当我尝试从python或Windows资源管理器中删除监视文件夹时,我得到:

WindowsError:[错误32]进程无法访问该文件,因为它正由另一个进程使用:'c:\ users \ user \ appdata \ local \ temp \ new_dir'

我相信这是有道理的,但我该如何解决这个问题呢?因为我的应用程序应该允许用户删除监视文件夹。我尝试了异步方法http://www.themacaque.com/?p=859的解决方案,但它没有帮助。

提前致谢!

3 个答案:

答案 0 :(得分:3)

来自this blog post

  

[ReadDirectoryChangesW]的另一个潜在缺陷是引用的目录本身现在“正在使用”,因此无法删除。要监视目录中的文件并仍然允许删除目录,您必须监视父目录及其子目录。

该帖子还提供了有关正确使用ReadDirectoryChangesW

的更多详细信息

答案 1 :(得分:2)

ReadDirectoryChangesW

下删除已观看的文件夹 IS

"Understanding ReadDirectoryChangesW - Part 2" by Jim Beveridge(正如Artomegus所提到的)是解决此问题的非常好的背景,但解释FILE_SHARE_DELETE用法的说法具有误导性。

我的测试,使用FILE_SHARE_DELETE实际上允许删除/重命名监视文件夹。 (换句话说,您不需要“观看父文件夹”作为唯一选项。)

以下是工作代码段(从这个非常优秀的"Watch a Directory for Changes" by Tim Golden

中大量编辑和借用
# License is same as snippets on this page
# http://timgolden.me.uk/python/win32_how_do_i/watch_directory_for_changes.html
# In other words, bug Tim Golden to publish a license for his snippets
def windows_watch_path(watched_path):
    import win32file
    import win32con

    ACTIONS = {
        1 : "Created",
        2 : "Deleted",
        3 : "Updated",
        4 : "RenamedFrom",
        5 : "RenamedTo"
    }
    # Thanks to Claudio Grondi for the correct set of numbers
    FILE_LIST_DIRECTORY = 0x0001

    try:
        hDir = win32file.CreateFile (
            watched_path
            , FILE_LIST_DIRECTORY
            , win32con.FILE_SHARE_READ | 
              win32con.FILE_SHARE_WRITE | 
              win32con.FILE_SHARE_DELETE
            , None
            , win32con.OPEN_EXISTING
            , win32con.FILE_FLAG_BACKUP_SEMANTICS
            , None
        )
    except:
        # either it does not exist by this time, or some other issue... blah.
        # we'll just say "it 'changed' from 'some other expected state'"
        return [[watched_path, '', ACTIONS[2]]]

    results = win32file.ReadDirectoryChangesW (
        hDir,
        1024,
        True,
        win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
        win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
        win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
        win32con.FILE_NOTIFY_CHANGE_SIZE |
        win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
        win32con.FILE_NOTIFY_CHANGE_SECURITY,
        None,
        None
    )

    files_changed = []
    for action, fn in results:
        files_changed.append(
            [
                watched_path
                , fn
                , ACTIONS[action]
            ]
        )
        # print fullfn, ACTIONS.get(action, "Unknown")
    return files_changed

答案 2 :(得分:0)

好的,这个问题并不容易解决......在我的案例中(http://www.themacaque.com/?p=859),我忽略了允许重命名或删除目录的事实。

允许用户重命名监视文件夹的操作方法是使用路径祖先上的ReadDirectoryChangesW根据您正在观看的路径监视和过滤事件。我已经实现了一种新的方式来执行使用twisted来执行事件的处理。有了这个解决方案,你可以在以下情况下观察祖先:

  1. 你的文件夹没有太多的兄弟可以忽略。您不希望执行大量操作来过滤您不感兴趣的事件。
  2. 如果用户无法移除祖先,则没有问题。
  3. 在Windows上的Ubuntu One代码中,我们一直在处理这个问题,我们已经实现了一个很好的解决方案,你可以看看。它遵循一点点linux上pyinotify的实现,它带有一个处理器,允许你用一个回调来挂钩一个对象,这些回调将根据扭曲的反应堆主循环中的事件进行调用。看看那段代码,它可能对你有帮助。

    我迟到的任何问题都在我的博客或irc中知道(在#ubuntuone或#pyar的freenode中)我的昵称是mandel;)