微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么ReadDirectoryChangesW会忽略事件?

我使用ReadDirectoryChangesW来监视一个指定的目录,并在检测到更改时更新索引结构。 我使用下面的代码(大致)

var InfoPointer : PFileNotify@R_136_4045@ion; NextOffset : DWORD; ... while (not Terminated) do begin if ReadDirectoryChangesW (FDirHandle,FBuffer,FBufferLength,True,FFilter,@BytesRead,@FOverlap,nil) then begin WaitResult := WaitForMultipleObjects (2,@FEventArray,False,INFINITE); if (WaitResult = waitFileChange) then begin InfoPointer := FBuffer; repeat NextOffset := InfoPointer.NextEntryOffset; ... PByte (InfoPointer) := PByte (InfoPointer) + NextOffset; until NextOffset = 0; end; end; end;

filter是

FFilter := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE;

和目录句柄是这样获得的:

FDirHandle := CreateFile (PChar (FDirectoryWatch.WatchedDirectory),FILE_LIST_DIRECTORY or GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,nil,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED,0);

当我删除多个文件,我只得到一个事件,NextOffset是0! 而当我删除一个目录,我只得到一个目录的事件。 如果我想要在目录中的每个文件一个事件呢?

文件系统中随机select一个文件

在Windows中识别文件types

为什么Walkingfiletree第二次更快?

Windows不变的文化之谜

如何在linux中连续磁盘块中存储文件

任何帮助,将不胜感激。

将statvfs转换为正确的百分比

在Linux中,符号链接的值是否可以比PATH_MAX长?

即使文件不可读,Java – file.length()也会返回

如何列出目录树中的所有二进制文件扩展名?

如何检查块是否存在于一个稀疏文件中(用于简单的写时拷贝)?

在我看来,您正在混合使用ReadDirectoryChangesW()的各种方法,您在打开目录时都指定FILE_FLAG_OVERLAPPED标志,并提供一个指向lpOverlapped参数的指针,这意味着您要等待结构中的事件并处理异步I / O; 同时在工作线程的循环中调用ReadDirectoryChangesW() 。 我会再次尝试使用lpOverlapped设置为零 ,因为你有一个专用的线程,可以使用同步模式。

在ReadDirectoryChangesW() API函数的文档中描述了使用它的不同方式。 请注意,缓冲区溢出也是可能的,所以更改事件可能会丢失。 也许你应该重新思考你单纯依靠这个功能的策略,比较目录内容的快照也可以。

编辑:

你编辑的代码看起来更好。 但是在我的测试中, ReadDirectoryChangesW()确实按照广告方式工作,在返回的缓冲区中有几个数据项,或者有多个缓冲区需要处理。 这取决于时间,在Delphi中打断点后,我得到了一个缓冲区中的几个条目。

为了完整起见,我附上了使用Delphi 5实现的测试代码

type TWatcherThread = class(TThread) private fChangeHandle: THandle; fDirHandle: THandle; fShutdownHandle: THandle; protected procedure Execute; override; public constructor Create(ADirectoryToWatch: string); destructor Destroy; override; procedure Shutdown; end; constructor TWatcherThread.Create(ADirectoryToWatch: string); const FILE_LIST_DIRECTORY = 1; begin inherited Create(TRUE); fChangeHandle := CreateEvent(nil,FALSE,nil); fDirHandle := CreateFile(PChar(ADirectoryToWatch),0); fShutdownHandle := CreateEvent(nil,nil); Resume; end; destructor TWatcherThread.Destroy; begin if fDirHandle <> INVALID_HANDLE_VALUE then CloseHandle(fDirHandle); if fChangeHandle <> 0 then CloseHandle(fChangeHandle); if fShutdownHandle <> 0 then CloseHandle(fShutdownHandle); inherited Destroy; end; procedure TWatcherThread.Execute; type PFileNotify@R_136_4045@ion = ^TFileNotify@R_136_4045@ion; TFileNotify@R_136_4045@ion = record NextEntryOffset: DWORD; Action: DWORD; FileNameLength: DWORD; FileName: WideChar; end; const BufferLength = 65536; var Filter,BytesRead: DWORD; InfoPointer: PFileNotify@R_136_4045@ion; Offset,NextOffset: DWORD; Buffer: array[0..BufferLength - 1] of byte; Overlap: TOverlapped; Events: array[0..1] of THandle; WaitResult: DWORD; FileName,s: string; begin if fDirHandle <> INVALID_HANDLE_VALUE then begin Filter := FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_DIR_NAME or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE; FillChar(Overlap,SizeOf(TOverlapped),0); Overlap.hEvent := fChangeHandle; Events[0] := fChangeHandle; Events[1] := fShutdownHandle; while not Terminated do begin if ReadDirectoryChangesW (fDirHandle,@Buffer[0],BufferLength,TRUE,Filter,@Overlap,nil) then begin WaitResult := WaitForMultipleObjects(2,@Events[0],INFINITE); if WaitResult = WAIT_OBJECT_0 then begin InfoPointer := @Buffer[0]; Offset := 0; repeat NextOffset := InfoPointer.NextEntryOffset; FileName := WideCharLenToString(@InfoPointer.FileName,InfoPointer.FileNameLength); SetLength(FileName,StrLen(PChar(FileName))); s := Format('[%d] Action: %.8xh,File: "%s"',[Offset,InfoPointer.Action,FileName]); OutputDebugString(PChar(s)); PByte(InfoPointer) := PByte(DWORD(InfoPointer) + NextOffset); Offset := Offset + NextOffset; until NextOffset = 0; end; end; end; end; end; procedure TWatcherThread.Shutdown; begin Terminate; if fShutdownHandle <> 0 then SetEvent(fShutdownHandle); end; //////////////////////////////////////////////////////////////////////////////// procedure TForm1.FormCreate(Sender: TObject); begin fThread := TWatcherThread.Create('D:Temp'); end; procedure TForm1.FormDestroy(Sender: TObject); begin if fThread <> nil then begin TWatcherThread(fThread).Shutdown; fThread.Free; end; end;

删除一个目录确实只会返回一个改变,对于其中包含的文件没有任何改变。 但它是有道理的,因为你只看到父目录的句柄。 如果您需要子目录的通知,您可能还需要观看它们。

我们也遇到了同样的问题,尤其是在同时发生很多变化的情况下。 将500个文件复制到受监视的目录。

最后我们找到了Cromis并使用了Directory手表 。 我们再也没有回头看过。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐