【问题标题】:ReadDirectoryChangesW blocks deleting the watched directoryReadDirectoryChangesW 阻止删除监视的目录
【发布时间】:2011-07-26 10:19:52
【问题描述】:

我正在尝试使用 ReadDirectoryChangesW API 使用 Python 在 Windows 上查看创建/删除/重命名更改的目录。这是我的代码,它工作正常:

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的解决方案,但没有帮助。

提前致谢!

【问题讨论】:

    标签: python winapi readdirectorychangesw


    【解决方案1】:

    来自this blog post

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

    该帖子还提供了有关正确使用 ReadDirectoryChangesW 的更多详细信息

    【讨论】:

    • 感谢您的回答!我找到了那个帖子,但显然错过了那个块。
    【解决方案2】:

    ReadDirectoryChangesW下可以删除被监视的文件夹IS

    "Understanding ReadDirectoryChangesW - Part 2" by Jim Beveridge 是(正如 Artomegus 提到的)这个问题的一个很好的背景,但是解释 FILE_SHARE_DELETE 用法的声明是误导性的。

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

    这是工作的 sn-p(编辑并大量借用了这个原本非常出色的 "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
    

    【讨论】:

      【解决方案3】:

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

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

      1. 您的文件夹没有太多可以忽略的兄弟。您不希望执行大量操作来过滤您不感兴趣的事件。
      2. 如果用户无法移除祖先,也没有问题。

      在 Windows 上的 Ubuntu One 的代码中,我们一直在处理这个问题,我们已经实现了一个很好的解决方案,您可以看看。它遵循了 linux 上 pyinotify 的一些实现,该处理器允许您使用回调挂钩对象,该回调将根据扭曲反应堆主循环中的事件被调用。看看那个代码,它可能对你有帮助。

      我的博客或 irc(在 #ubuntuone 或 #pyar 的 freenode 中)我的昵称是 mandel ;)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-17
        • 1970-01-01
        相关资源
        最近更新 更多