问题
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!
回答1:
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
回答2:
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
回答3:
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:
- 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.
- 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 ;)
来源:https://stackoverflow.com/questions/6828544/readdirectorychangesw-blocks-deleting-the-watched-directory