admin管理员组

文章数量:1537014

一、Windows提供了几种方式对文件和目录进行监控,包括:FindFirstChangeNotification、ReadDirectoryChangesW、变更日志(Change Journal)等。
(1)FindFirstChangeNotification函数,可以监控到目标目录及其子目录中所有文件的变化,但不能监控到具体是哪一个文件发生改变。
(2)ReadDirectoryChangesW 能监控到目标目录下某一文件发生改变,并且可以知道发生变化的是哪一个文件。
注意,FindFirstChangeNotification 和 ReadDirectoryChangesW 是互斥的,不能同时使用。
(3)变更日志(Change Journal)可以跟踪每一个变更的细节,即使你的软件没有运行。很帅的技术,但也相当难用。

二、ReadDirectoryChangesW定义说明

ReadDirectoryChangesWWindows提供一个API,用于读取文件夹的磁盘变更。该API很实用,目前市面上已知的所有运行在用户态同步应用,都绕不开这个接口。但正确使用该API相对来说比较复杂,该接口能真正考验一个Windows开发人员对线程、异步IO、可提醒IO、IO完成端口等知识的掌握情况,如果读者还不熟悉这些技术,请先补充一下相关背景知识。

感谢 jimbeveridge (Multithreading Applications in Win32的作者)的精彩文章Understanding ReadDirectoryChangesW,建议读者也去读一下。jimbeveridge使用了可提醒IO实现对文件夹的磁盘监控。为了更深入的了解该API,在jimbeveridge基础上,我提供另一种IO完成端口异步模型,实现对文件夹的磁盘监控。

相关代码请参考github, 代码未经过充分测试,仅提供参考。

API简介

其函数原型为:

BOOL WINAPI ReadDirectoryChangesW(
  _In_        HANDLE                          hDirectory,
  _Out_       LPVOID                          lpBuffer,
  _In_        DWORD                           nBufferLength,
  _In_        BOOL                            bWatchSubtree,
  _In_        DWORD                           dwNotifyFilter,
  _Out_opt_   LPDWORD                         lpBytesReturned,
  _Inout_opt_ LPOVERLAPPED                    lpOverlapped,
  _In_opt_    LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

函数各个参数说明可以参考MSDN,由于该函数提供了丰富的调用方式,包括同步和异步方式。异步方式可以采用以下三种方式获取完成通知:

  • OVERLAPPED结构中的hEvent成员中设置一个事件句柄,使用GetOverlappedResult 获取完成结果。
  • 使用可提醒IO, 在参数lpComletionRoutine指定一个回调函数。当ReadDirectoryChangesW异步请求完成时,驱动会将指定的回调函数(lpComletionRoutine)投递到调用线程的APC队列中。对可提醒IO,OVERLAPPED结构中的hEvent 字段操作系统并不使用,我们可以自己使用该值。
  • 使用IO完成端口,通过GetQueuedComletionStatus获取完成结果。

同步方式比较简单,但不具可伸缩性,在实际应用中并不多。不同的异步方式也影响到线程模型的选择,所以如何正确使用该函数其实并不容易。

ReadDirectoryChangesW的第一参数是一个文件夹句柄,所以首先需要正确打开一个文件夹,接下来主要描述怎样正确使用可提醒IOIO完成端口方式调用ReadDirectoryChangesW,最后再谈谈怎样得体地退出线程(也是最容易被忽略的点);

打开文件夹

打开一个文件夹使用CreateFile,函数

本文标签: 文件夹中Windows