gpt4 book ai didi

python - win32file.ReadDirectoryChangesW找不到所有移动的文件

转载 作者:行者123 更新时间:2023-12-01 09:32:57 28 4
gpt4 key购买 nike

早上好,

我在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!


如何检测所有丢失的文件?

最佳答案

[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中可用。如果传输的字节数为零,则缓冲区太大,系统无法分配,或者缓冲区太小,无法提供有关目录或子树中发生的所有更改的详细信息。在这种情况下,您应该通过列举目录或子树来计算更改。



这在某种程度上证实了我以前的假设


“缓冲区太大,系统无法分配”-也许分配前一点的缓冲区时,是否考虑了nBufferLength?




无论如何,我接受了您的代码并对其进行了“一点点”更改。

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()


笔记:


尽可能使用常量
将您的代码分解为功能,使其成为模块化(并避免重复)
添加了打印语句以增加输出
添加了异步功能(因此,如果目录中没有活动,脚本不会永远挂起)
添加了一种在用户按下ESC时退出的方式(当然,在同步模式下,目录中的事件也必须发生)
玩不同的值以获得不同的结果


输出:




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



备注:


使用了包含10个不同名称文件的目录测试(重复0123456789)
有4次运行:


同步


512B缓冲区
64K缓冲区

异步


512B缓冲区
64K缓冲区


对于每次(以上)运行,文件均为(使用Windows Commander进行操作):


从目录移动(涉及删除)
移动(返回)到目录(涉及添加)

每种组合仅运行一次,到目前为止还不能作为基准,但是我多次运行了脚本,并且模式趋于一致
删除文件在运行之间的差异不会太大,这意味着事件会在(极短的时间内)均匀分布
另一方面,添加文件取决于缓冲区大小。另一个值得注意的是,每次添加都会有2个事件
从性能的角度来看,异步模式并没有带来任何改进(正如我所期望的),相反,它倾向于使速度变慢。但是最大的好处是有可能在超时时正常退出(异常中断可能会使资源锁定,直到程序退出(有时甚至超出!))


最重要的是,没有避免丢失事件的方法。可以通过增加生成的事件数量来“击败”采取的每项措施。

减少损失:


缓冲区大小。这是您所遇到的(主要)问题。不幸的是,文档的内容并不太清楚,没有关于应该多大的指导原则。浏览C论坛我注意到64K是一个普遍的价值。然而:


不可能有巨大的缓冲区,并且在失败之前无法减小缓冲区的大小,因为这将意味着丢失所有在计算缓冲区大小时生成的事件
即使64k足以容纳(几次)我在测试中生成的所有事件,但仍有一些丢失。也许是因为我在一开始就谈到“神奇”的缓冲

尽可能减少事件数量。在您的情况下,我注意到您仅对添加和删除事件(FILE_ACTION_ADDED和FILE_ACTION_REMOVED)感兴趣。仅向ReadDirectoryChangesW指定适当的FILE_NOTIFY_CHANGE_ *标志(例如,您并不关心FILE_ACTION_MODIFIED,但是在添加文件时会收到它)
尝试将目录内容拆分为几个子目录并同时监视它们。例如,如果您仅关心一个目录及其一堆子目录中发生的更改,则递归监视整个树没有意义,因为它很可能会产生很多无用的事件。无论如何,如果并行处理,则不要因为GIL而使用线程!!! ( [Python.Wiki]: GlobalInterpreterLock)。使用 [Python 2.Docs]: multiprocessing - Process-based “threading” interface代替
提高在循环中运行的代码的速度,以便它在ReadDirectoryChangesW之外花费尽可能少的时间(当生成的事件可能会使缓冲区溢出时)。当然,以下某些项目可能影响不大,并且(也有一些不良影响),但无论如何我还是列出它们:


尽量减少处理,并尝试延迟处理。也许在另一个过程中做(由于GIL)
摆脱所有类似打印的陈述
而不是例如 win32con.FILE_NOTIFY_CHANGE_FILE_NAME在脚本的开头使用 from win32con import FILE_NOTIFY_CHANGE_FILE_NAME,并且仅在循环中使用FILE_NOTIFY_CHANGE_FILE_NAME(以避免在模块中进行变量查找)
不要使用函数(因为像说明一样调用/重拨)-不确定
尝试使用 win32file.GetQueuedCompletionStatus方法获取结果(仅异步)
由于时间的推移,事情往往会变得更好(当然也有例外),请尝试切换到较新的Python版本。也许它将运行得更快
使用C-这可能是不希望的,但是它可能会带来一些好处:


PyWin32不会在Python和C之间来回转换-但是我没有使用探查器来检查它们花费了多少时间。
lpCompletionRoutine(PyWin32不提供)也可以使用,也许更快
作为替代方案,可以使用ctypes调用C,但这需要一些工作,我觉得这不值得

关于python - win32file.ReadDirectoryChangesW找不到所有移动的文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49799109/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com