ReadDirectoryChangesW 阻止删除监视的目录

发布于 2024-11-26 09:18:27 字数 1281 浏览 0 评论 0原文

我正在尝试使用 ReadDirectoryChangesW API 在 Windows 上使用 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: [Error 32] 该进程无法访问该文件,因为它正在使用通过另一个进程: 'c:\users\user\appdata\local\temp\new_dir'

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

提前致谢!

I am trying to watch a directory for create/delete/rename changes on windows with python using the ReadDirectoryChangesW API. This is my code and it is working fine:

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)

However, when I try to delete the watched folder from python or from windows explorer, I get:

WindowsError: [Error 32] The process cannot access the file because it is being used by another process: 'c:\users\user\appdata\local\temp\new_dir'

I believe this makes sense, but how should I solve this? Because my application should allow the user to remove a watched folder. I tried the solution for the asynchronous method http://www.themacaque.com/?p=859, but it didn't help.

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

天涯沦落人 2024-12-03 09:18:27

来自这篇博文

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

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

From this blog post:

Another potential pitfall of [ReadDirectoryChangesW] is that the referenced directory itself is now "in use" and so can't be deleted. To monitor files in a directory and still allow the directory to be deleted, you would have to monitor the parent directory and its children.

The post also provides some more details on proper use of ReadDirectoryChangesW

夏有森光若流苏 2024-12-03 09:18:27

可以在 ReadDirectoryChangesW

Jim Beveridge 的“理解 ReadDirectoryChangesW - 第 2 部分” 是(正如 Artomegus 提到的)这个问题的一个非常好的背景,但是解释的声明FILE_SHARE_DELETE 的用法具有误导性。

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

这是工作片段(经过编辑并大量借用了这个优秀的 “监视目录的更改”作者: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

Deleting the watched folder IS possible under ReadDirectoryChangesW

"Understanding ReadDirectoryChangesW - Part 2" by Jim Beveridge is (as Artomegus mentioned) a very good background for this problem, but the statement explaining FILE_SHARE_DELETE usage is misleading.

I my tests, use of FILE_SHARE_DELETE actually allows deletion / rename of the watched folder. (In other words, you don't need to "watch parent folder" as the only option.)

Here is the working snippet (edited and borrowed heavily from this otherwise excellent "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
痴情换悲伤 2024-12-03 09:18:27

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

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

  1. 您的文件夹没有太多需要忽略的兄弟。您不想执行大量操作来过滤您不感兴趣的事件。
  2. 如果用户无法删除祖先,则没有问题。

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

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

Ok, to this is not simple to solve... In my case (http://www.themacaque.com/?p=859) I ignored the fact of allowing to rename or remove the directory.

What you could do to allow the user to rename the watch folder is to use the ReadDirectoryChangesW on the ancestor of the path to watch and filter the events according to the paths you are watching. I have implemented a new way to perform the watching using twisted to perform the processing of the events. With that solution you could be wathching the ancestors if:

  1. You folder does not have too many brothers to ignore. You do not want to be performing lots and lots of operations to filter events you are no interested in.
  2. There is no problem if the user cannot remove the ancestor.

In the code of Ubuntu One on windows we have been dealing with this problem and we have implemented a nice solution that you can take a look at. It follows a little the implementation of pyinotify on linux with a processor that will allow you to hook an object with callbacks that will be called according to the event in the twisted reactors main loop. Take a look at that code, it might help you.

Any problem late me know either in my blog or in irc (in freenode at #ubuntuone or #pyar) my nickname is mandel ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文