早上好,
我遇到了一个我在Python中创建的程序的一个特殊问题。看来,当我将文件从一个位置拖放到另一个位置时,并非所有文件都被模块注册为事件。
我一直在使用win32file和win32con来尝试获取与将文件从一个位置移动到另一个位置以进行处理相关的所有事件。
以下是我的检测代码的一小部分:
import win32file
import win32con
def main():
path_to_watch = 'D:\\'
_file_list_dir = 1
# Create a watcher handle
_h_dir = win32file.CreateFile(
path_to_watch,
_file_list_dir,
win32con.FILE_SHARE_READ |
win32con.FILE_SHARE_WRITE |
win32con.FILE_SHARE_DELETE,
None,
win32con.OPEN_EXISTING,
win32con.FILE_FLAG_BACKUP_SEMANTICS,
None
)
while 1:
results = win32file.ReadDirectoryChangesW(
_h_dir,
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
)
for _action, _file in results:
if _action == 1:
print 'found!'
if _action == 2:
print 'deleted!'
我拖放了7个文件,但只发现了4个。
# found!
# found!
# found!
# found!
如何检测所有丢弃的文件?
答案 0 :(得分:1)
[ActiveState.Docs]: win32file.ReadDirectoryChangesW(这是我能为[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions找到的最佳文档)是[MS.Docs]: ReadDirectoryChangesW function的包装器。这是它所说的内容(关于缓冲区):
一般
当您第一次调用 ReadDirectoryChangesW 时,系统会分配一个缓冲区来存储更改信息。此缓冲区与目录句柄关联,直到它关闭并且其大小在其生命周期内不会更改。在对此函数的调用之间发生的目录更改将添加到缓冲区,然后在下一次调用时返回。如果缓冲区溢出,则丢弃缓冲区的全部内容, lpBytesReturned 参数包含零, ReadDirectoryChangesW 函数失败,错误代码为 ERROR_NOTIFY_ENUM_DIR
我的理解是这是一个不同的缓冲区,而不是作为参数传递的缓冲区( lpBuffer ):
将前者传递给 ReadDirectoryChangesW 的每次调用(可以为每次调用传递不同的缓冲区(不同大小))
后者由系统分配,前者在功能调用之前明确分配(由用户)
和是在函数调用之间存储数据(可能是某种原始格式)的,并且在调用函数时,缓冲区内容被复制(并格式化)为 lpBuffer (如果没有在此期间飞越(并丢弃))
同步
同步完成成功后, lpBuffer 参数是格式化缓冲区,写入缓冲区的字节数可在 lpBytesReturned 中获得。如果传输的字节数为零,则缓冲区要么太大而不能分配系统,要么太小而无法提供有关目录或子树中发生的所有更改的详细信息。在这种情况下,您应该通过枚举目录或子树来计算更改。
这在某种程度上证实了我之前的假设
无论如何,我把你的代码改成了#34;有点"。
code.py :
import sys
import msvcrt
import pywintypes
import win32file
import win32con
import win32api
import win32event
FILE_LIST_DIRECTORY = 0x0001
FILE_ACTION_ADDED = 0x00000001
FILE_ACTION_REMOVED = 0x00000002
ASYNC_TIMEOUT = 5000
BUF_SIZE = 65536
def get_dir_handle(dir_name, async):
flags_and_attributes = win32con.FILE_FLAG_BACKUP_SEMANTICS
if async:
flags_and_attributes |= win32con.FILE_FLAG_OVERLAPPED
dir_handle = win32file.CreateFile(
dir_name,
FILE_LIST_DIRECTORY,
(win32con.FILE_SHARE_READ |
win32con.FILE_SHARE_WRITE |
win32con.FILE_SHARE_DELETE),
None,
win32con.OPEN_EXISTING,
flags_and_attributes,
None
)
return dir_handle
def read_dir_changes(dir_handle, size_or_buf, overlapped):
return win32file.ReadDirectoryChangesW(
dir_handle,
size_or_buf,
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),
overlapped,
None
)
def handle_results(results):
for item in results:
print(" {} {:d}".format(item, len(item[1])))
_action, _ = item
if _action == FILE_ACTION_ADDED:
print(" found!")
if _action == FILE_ACTION_REMOVED:
print(" deleted!")
def esc_pressed():
return msvcrt.kbhit() and ord(msvcrt.getch()) == 27
def monitor_dir_sync(dir_handle):
idx = 0
while True:
print("Index: {:d}".format(idx))
idx += 1
results = read_dir_changes(dir_handle, BUF_SIZE, None)
handle_results(results)
if esc_pressed():
break
def monitor_dir_async(dir_handle):
idx = 0
buffer = win32file.AllocateReadBuffer(BUF_SIZE)
overlapped = pywintypes.OVERLAPPED()
overlapped.hEvent = win32event.CreateEvent(None, False, 0, None)
while True:
print("Index: {:d}".format(idx))
idx += 1
read_dir_changes(dir_handle, buffer, overlapped)
rc = win32event.WaitForSingleObject(overlapped.hEvent, ASYNC_TIMEOUT)
if rc == win32event.WAIT_OBJECT_0:
bufer_size = win32file.GetOverlappedResult(dir_handle, overlapped, True)
results = win32file.FILE_NOTIFY_INFORMATION(buffer, bufer_size)
handle_results(results)
elif rc == win32event.WAIT_TIMEOUT:
#print(" timeout...")
pass
else:
print("Received {:d}. Exiting".format(rc))
break
if esc_pressed():
break
win32api.CloseHandle(overlapped.hEvent)
def monitor_dir(dir_name, async=False):
dir_handle = get_dir_handle(dir_name, async)
if async:
monitor_dir_async(dir_handle)
else:
monitor_dir_sync(dir_handle)
win32api.CloseHandle(dir_handle)
def main():
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
async = True
print("Attempting {}ynchronous mode using a buffer {:d} bytes long...".format("As" if async else "S", BUF_SIZE))
monitor_dir(".\\test", async=async)
if __name__ == "__main__":
main()
备注强>:
<强>输出强>:
e:\Work\Dev\StackOverflow\q049799109>dir /b test 0123456789.txt 01234567890123456789.txt 012345678901234567890123456789.txt 0123456789012345678901234567890123456789.txt 01234567890123456789012345678901234567890123456789.txt 012345678901234567890123456789012345678901234567890123456789.txt 0123456789012345678901234567890123456789012345678901234567890123456789.txt 01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt e:\Work\Dev\StackOverflow\q049799109> e:\Work\Dev\StackOverflow\q049799109>"C:\Install\x64\HPE\OPSWpython\2.7.10__00\python.exe" code.py Python 2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)] on win32 Attempting Synchronous mode using a buffer 512 bytes long... Index: 0 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 deleted! Index: 1 (2, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 deleted! Index: 2 (2, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 deleted! Index: 3 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 deleted! (2, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 deleted! Index: 4 (2, u'01234567890123456789012345678901234567890123456789.txt') 54 deleted! Index: 5 (2, u'0123456789012345678901234567890123456789.txt') 44 deleted! (2, u'012345678901234567890123456789.txt') 34 deleted! Index: 6 (2, u'01234567890123456789.txt') 24 deleted! (2, u'0123456789.txt') 14 deleted! Index: 7 (1, u'0123456789.txt') 14 found! Index: 8 (3, u'0123456789.txt') 14 Index: 9 (1, u'01234567890123456789.txt') 24 found! Index: 10 (3, u'01234567890123456789.txt') 24 (1, u'012345678901234567890123456789.txt') 34 found! (3, u'012345678901234567890123456789.txt') 34 (1, u'0123456789012345678901234567890123456789.txt') 44 found! Index: 11 (3, u'0123456789012345678901234567890123456789.txt') 44 (1, u'01234567890123456789012345678901234567890123456789.txt') 54 found! (3, u'01234567890123456789012345678901234567890123456789.txt') 54 Index: 12 Index: 13 (1, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 found! Index: 14 Index: 15 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 found! Index: 16 (3, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 Index: 17 (1, u'a') 1 found! Index: 18 (3, u'a') 1 e:\Work\Dev\StackOverflow\q049799109> e:\Work\Dev\StackOverflow\q049799109>"C:\Install\x64\HPE\OPSWpython\2.7.10__00\python.exe" code.py Python 2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)] on win32 Attempting Synchronous mode using a buffer 65536 bytes long... Index: 0 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 deleted! Index: 1 (2, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 deleted! Index: 2 (2, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 deleted! Index: 3 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 deleted! Index: 4 (2, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 deleted! Index: 5 (2, u'01234567890123456789012345678901234567890123456789.txt') 54 deleted! Index: 6 (2, u'0123456789012345678901234567890123456789.txt') 44 deleted! Index: 7 (2, u'012345678901234567890123456789.txt') 34 deleted! (2, u'01234567890123456789.txt') 24 deleted! (2, u'0123456789.txt') 14 deleted! Index: 8 (1, u'0123456789.txt') 14 found! Index: 9 (3, u'0123456789.txt') 14 Index: 10 (1, u'01234567890123456789.txt') 24 found! Index: 11 (3, u'01234567890123456789.txt') 24 Index: 12 (1, u'012345678901234567890123456789.txt') 34 found! Index: 13 (3, u'012345678901234567890123456789.txt') 34 Index: 14 (1, u'0123456789012345678901234567890123456789.txt') 44 found! Index: 15 (3, u'0123456789012345678901234567890123456789.txt') 44 Index: 16 (1, u'01234567890123456789012345678901234567890123456789.txt') 54 found! (3, u'01234567890123456789012345678901234567890123456789.txt') 54 Index: 17 (1, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 found! (3, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 found! Index: 18 (3, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 (1, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 found! (3, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 (1, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 found! (3, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 found! (3, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 Index: 20 (2, u'a') 1 deleted! e:\Work\Dev\StackOverflow\q049799109> e:\Work\Dev\StackOverflow\q049799109>"C:\Install\x64\HPE\OPSWpython\2.7.10__00\python.exe" code.py Python 2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)] on win32 Attempting Asynchronous mode using a buffer 512 bytes long... Index: 0 Index: 1 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 deleted! Index: 2 (2, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 deleted! Index: 3 (2, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 deleted! Index: 4 (2, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 deleted! Index: 5 (2, u'01234567890123456789012345678901234567890123456789.txt') 54 deleted! Index: 6 (2, u'0123456789012345678901234567890123456789.txt') 44 deleted! Index: 7 (2, u'012345678901234567890123456789.txt') 34 deleted! Index: 8 (2, u'01234567890123456789.txt') 24 deleted! Index: 9 (2, u'0123456789.txt') 14 deleted! Index: 10 Index: 11 Index: 12 (1, u'0123456789.txt') 14 found! Index: 13 (1, u'01234567890123456789.txt') 24 found! Index: 14 (1, u'012345678901234567890123456789.txt') 34 found! Index: 15 (3, u'012345678901234567890123456789.txt') 34 Index: 16 (1, u'0123456789012345678901234567890123456789.txt') 44 found! (3, u'0123456789012345678901234567890123456789.txt') 44 Index: 17 Index: 18 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 found! Index: 19 Index: 20 (1, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 found! Index: 21 Index: 22 Index: 23 Index: 24 e:\Work\Dev\StackOverflow\q049799109> e:\Work\Dev\StackOverflow\q049799109>"C:\Install\x64\HPE\OPSWpython\2.7.10__00\python.exe" code.py Python 2.7.10 (default, Mar 8 2016, 15:02:46) [MSC v.1600 64 bit (AMD64)] on win32 Attempting Asynchronous mode using a buffer 65536 bytes long... Index: 0 Index: 1 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 deleted! Index: 2 (2, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 deleted! Index: 3 (2, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 deleted! Index: 4 (2, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 deleted! Index: 5 (2, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 deleted! Index: 6 (2, u'01234567890123456789012345678901234567890123456789.txt') 54 deleted! Index: 7 (2, u'0123456789012345678901234567890123456789.txt') 44 deleted! Index: 8 (2, u'012345678901234567890123456789.txt') 34 deleted! (2, u'01234567890123456789.txt') 24 deleted! Index: 9 (2, u'0123456789.txt') 14 deleted! Index: 10 Index: 11 Index: 12 (1, u'0123456789.txt') 14 found! Index: 13 (1, u'01234567890123456789.txt') 24 found! Index: 14 (1, u'012345678901234567890123456789.txt') 34 found! Index: 15 (3, u'012345678901234567890123456789.txt') 34 (1, u'0123456789012345678901234567890123456789.txt') 44 found! (3, u'0123456789012345678901234567890123456789.txt') 44 Index: 16 (1, u'01234567890123456789012345678901234567890123456789.txt') 54 found! (3, u'01234567890123456789012345678901234567890123456789.txt') 54 (1, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 found! (3, u'012345678901234567890123456789012345678901234567890123456789.txt') 64 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 found! Index: 17 (3, u'0123456789012345678901234567890123456789012345678901234567890123456789.txt') 74 (1, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 found! (3, u'01234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 84 (1, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 found! (3, u'012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 94 (1, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 found! (3, u'0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789.txt') 104 Index: 18 Index: 19
<强>说明强>:
底线是没有避免丢失事件的方法。采取的每一项措施都可以被打败&#34;通过增加生成事件的数量。
尽量减少损失:
缓冲区大小。这是您案件中的(主要)问题。不幸的是,文档不太清楚,没有关于它应该有多大的指导。浏览 C 论坛我注意到 64K 是一个常见值。但是:
不可能有一个巨大的缓冲区,并且在成功之前无法减小其大小,因为这意味着在计算缓冲区大小时会丢失所有生成的事件
< / LI>即使 64k 足以容纳(多次)我在测试中生成的所有事件,但有些事件仍然丢失。也许那是因为&#34;魔法&#34;我在开头谈到的缓冲区
尽可能减少事件数量。在您的情况下,我注意到您只对添加和删除事件感兴趣( FILE_ACTION_ADDED 和 FILE_ACTION_REMOVED )。仅为 ReadDirectoryChangesW 指定相应的 FILE_NOTIFY_CHANGE _ * 标志(例如,您不关心 FILE_ACTION_MODIFIED ,但是您在添加时会收到它文件)
尝试在几个子目录中拆分目录内容并同时监视它们。例如,如果您只关心在一个目录和一堆子目录中发生的更改,那么递归监视整个树就没有意义,因为它很可能会产生大量无用的事件。无论如何,如果并行处理,不会因为 GIL !!! ([Python.Wiki]: GlobalInterpreterLock)而使用线程。请改用[Python 2]: multiprocessing - Process-based “threading” interface
提高在循环中运行的代码的速度,以便在 ReadDirectoryChangesW 之外花费尽可能少的时间(当生成的事件可能溢出缓冲区时)。当然,下面的一些项目可能会产生微不足道的影响,并且(也有一些不好的副作用)但我还是会列出它们:
尽可能减少处理并尝试延迟处理。也许在另一个过程中进行(因为 GIL )
摆脱所有 print 之类的陈述
而不是例如win32con.FILE_NOTIFY_CHANGE_FILE_NAME
在脚本开头使用from win32con import FILE_NOTIFY_CHANGE_FILE_NAME
,并且只在循环中使用 FILE_NOTIFY_CHANGE_FILE_NAME (以避免模块中的变量查找)
不要使用功能(因为调用 / ret 就像说明一样) - 不确定
尝试使用win32file.GetQueuedCompletionStatus
方法获取结果(仅 async )
由于时间往往会变得更好(当然也有例外),尝试切换到较新的 Python 版本。也许它会跑得更快
使用 C - 这可能是不受欢迎的,但它可能有一些好处:
python32 执行 Python 和 C 之间的来回转换 - 但我没有& #39;使用分析器检查花费的时间
lpCompletionRoutine ( pywin32 不提供)也可以使用,也许它更快
作为替代方案,可以使用 ctypes 调用 C ,但这需要一些工作,我觉得它不值得