当前位置: 首页 > ai >正文

windows平台监控目录、子目录下的文件变化

Windows平台下提供有多种不同方式去监控目录变化,这里主要讨论其中一种:

ReadDirectoryChangesW

一、函数原型

ReadDirectoryChangesW 是 Windows API 中用于监控目录变化的函数,支持实时获取目录内文件或子目录的创建、删除、修改等事件。以下是其核心参数和使用方法的详细说明:

1、原型

BOOL ReadDirectoryChangesW(HANDLE                hDirectory,LPVOID                lpBuffer,DWORD                 nBufferLength,BOOL                  bWatchSubtree,DWORD                 dwNotifyFilter,LPDWORD               lpBytesReturned,LPOVERLAPPED          lpOverlapped,LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

2、参数

​hDirectory​

  • ​作用​​:要监控的目录句柄,需通过 CreateFile 打开,并指定 FILE_LIST_DIRECTORY 访问权限

​lpBuffer​

  • ​作用​​:接收变更信息的缓冲区,需按 FILE_NOTIFY_INFORMATION 结构解析

​nBufferLength​

  • ​作用​​:缓冲区大小(字节)。若缓冲区不足,函数返回 TRUE 但 lpBytesReturned 为 0,需扩容后重试

bWatchSubtree​

  • ​作用​​:是否监控子目录。
    • TRUE:监控整个目录树(包括子目录)
    • FALSE:仅监控指定目录。

dwNotifyFilter​

  • ​作用​​:过滤监控事件类型,常用值组合:
FILE_NOTIFY_CHANGE_FILE_NAME |  // 文件名变化(创建/删除/重命名)
FILE_NOTIFY_CHANGE_LAST_WRITE | // 文件内容修改
FILE_NOTIFY_CHANGE_SIZE;        // 文件大小变化

​lpBytesReturned​

  • ​作用​​:输出参数,返回实际写入缓冲区的字节数。同步调用时有效,异步调用需忽略

​lpOverlapped​

  • ​作用​​:异步操作时使用的 OVERLAPPED 结构。需设置 hEvent 为事件句柄,或通过完成例程处理结果

​lpCompletionRoutine​

  • ​作用​​:异步完成时的回调函数,需配合 OVERLAPPED 使用

二、调用方式

1、同步调用​
  • ​特点​​:阻塞等待操作完成,适合简单场景。
  • ​示例​
DWORD dwBytes = 0;
if (ReadDirectoryChangesW(hDir, buffer, sizeof(buffer), TRUE, filter, &dwBytes, NULL, NULL)) {// 处理 buffer 中的变更事件
}
2、异步调用​
  • ​特点​​:非阻塞,通过事件或回调通知结果。
  • ​方法

1)事件通知

OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ReadDirectoryChangesW(..., &overlapped, NULL);
// 等待事件触发
WaitForSingleObject(overlapped.hEvent, INFINITE);

2)完成示例

VOID CALLBACK CompletionRoutine(DWORD dwErr, DWORD dwBytes, LPOVERLAPPED lpOverlapped) {// 处理完成后的逻辑
}
ReadDirectoryChangesW(..., NULL, CompletionRoutine);

3)IO完成端口

HANDLE hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
CreateIoCompletionPort(hDir, hIOCP, 0, 0);
ReadDirectoryChangesW(..., &overlapped, NULL);
GetQueuedCompletionStatus(hIOCP, &dwBytes, NULL, NULL, INFINITE);

三、代码实现

#include <Windows.h>
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>// 将宽字符字符串转换为UTF-8字符串,便于控制台输出
std::string wstring_to_utf8(const std::wstring& str) 
{std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;return converter.to_bytes(str);
}int main() 
{// 设置控制台输出为UTF-8,以便正确显示Unicode字符SetConsoleOutputCP(CP_UTF8);// 要监控的目录路径(请根据实际情况修改)const std::wstring directory = L"D:\\Testing";// 1. 打开目录句柄HANDLE hDir = CreateFile(directory.c_str(),FILE_LIST_DIRECTORY,         // 需要目录的读取权限FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // 共享模式NULL,                        // 默认安全属性OPEN_EXISTING,               // 打开现有目录FILE_FLAG_BACKUP_SEMANTICS | // 必须的目录访问标志FILE_FLAG_OVERLAPPED,        // 使用异步I/ONULL);if (hDir == INVALID_HANDLE_VALUE) {std::cerr << u8"无法打开目录。错误代码: " << GetLastError() << std::endl;return 1;}// 2. 创建事件对象用于异步I/O通知HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);if (!hEvent) {std::cerr << u8"创建事件失败。错误代码: " << GetLastError() << std::endl;CloseHandle(hDir);return 1;}// 3. 初始化OVERLAPPED结构OVERLAPPED overlapped = { 0 };overlapped.hEvent = hEvent;// 4. 定义缓冲区用于接收变更通知const DWORD bufferSize = 4096; // 4KB缓冲区BYTE buffer[bufferSize];// 5. 首次调用ReadDirectoryChangesW启动监控DWORD dwBytesReturned = 0;BOOL success = ReadDirectoryChangesW(hDir,buffer,bufferSize,TRUE, // 不监控子目录FILE_NOTIFY_CHANGE_FILE_NAME |  // 文件名变更(创建、删除、重命名)FILE_NOTIFY_CHANGE_DIR_NAME |   // 目录名变更FILE_NOTIFY_CHANGE_ATTRIBUTES |  // 文件属性变更FILE_NOTIFY_CHANGE_SIZE |  // 文件大小变更FILE_NOTIFY_CHANGE_LAST_WRITE |  // 最后写入时间变更FILE_NOTIFY_CHANGE_CREATION,     // 文件创建时间变更&dwBytesReturned,&overlapped,NULL);if (!success) {std::cerr << u8"ReadDirectoryChangesW初始化失败。错误代码: " << GetLastError() << std::endl;CloseHandle(hDir);CloseHandle(hEvent);return 1;}std::cout << u8"开始监控目录: " << wstring_to_utf8(directory) << std::endl;// 6. 主循环:等待事件并处理变更while (true) {// 等待事件触发(INFINITE表示永久等待)DWORD dwWaitStatus = WaitForSingleObject(hEvent, INFINITE);if (dwWaitStatus == WAIT_OBJECT_0) {DWORD dwBytesTransferred = 0;// 检查异步操作结果if (GetOverlappedResult(hDir, &overlapped, &dwBytesTransferred, FALSE)) {// 处理接收到的变更信息BYTE* p = buffer;while (true) {FILE_NOTIFY_INFORMATION* info = (FILE_NOTIFY_INFORMATION*)p;// 将宽字符文件名转换为字符串std::wstring fileName(info->FileName, info->FileNameLength / sizeof(WCHAR));// 解析事件类型std::string action;switch (info->Action) {case FILE_ACTION_ADDED:action = u8"新增文件";break;case FILE_ACTION_REMOVED:action = u8"删除文件";break;case FILE_ACTION_MODIFIED:action = u8"修改内容";break;case FILE_ACTION_RENAMED_OLD_NAME:action = u8"旧名称(重命名)";break;case FILE_ACTION_RENAMED_NEW_NAME:action = u8"新名称(重命名)";break;default:action = u8"未知操作";}// 输出到控制台std::cout << u8"[事件] " << action<< " -> " << wstring_to_utf8(fileName) << std::endl;// 检查是否还有后续条目if (info->NextEntryOffset == 0) {break;}p += info->NextEntryOffset;}}else {// 处理错误DWORD err = GetLastError();std::cerr << u8"获取异步结果失败。错误代码: " << err << std::endl;break;}// 重置事件并重新启动监控ResetEvent(hEvent);success = ReadDirectoryChangesW(hDir,buffer,bufferSize,TRUE,FILE_NOTIFY_CHANGE_FILE_NAME |FILE_NOTIFY_CHANGE_DIR_NAME |FILE_NOTIFY_CHANGE_ATTRIBUTES |FILE_NOTIFY_CHANGE_SIZE |FILE_NOTIFY_CHANGE_LAST_WRITE |FILE_NOTIFY_CHANGE_CREATION,&dwBytesReturned,&overlapped,NULL);if (!success) {DWORD err = GetLastError();std::cerr << u8"重新启动监控失败。错误代码: " << err << std::endl;break;}}else {// 等待失败std::cerr << u8"等待事件失败。错误代码: " << GetLastError() << std::endl;break;}}// 清理资源CloseHandle(hDir);CloseHandle(hEvent);return 0;
}

四、代码说明

1、目录打开:使用CreateFile以适当的权限打开目录,注意FILE_FLAG_BACKUP_SEMANTICS标志是访问目录所必需的。
2、异步I/O设置:通过OVERLAPPED结构和事件对象实现异步通知
3、监控事件类型:

  • FILE_NOTIFY_CHANGE_FILE_NAME:文件创建、删除、重命名
  • FILE_NOTIFY_CHANGE_DIR_NAME:目录创建、删除、重命名
  • 其他标志监控属性、大小、写入时间和创建时间变化

4、事件处理循环:

  • 使用WaitForSingleObject等待事件触发。
  • 解析FILE_NOTIFY_INFORMATION结构链表,处理每个变更事件。
  • 支持处理多条目通知(例如同时发生多个文件变更)。

5、错误处理:所有关键操作均检查返回值,确保错误能被及时发现。
6、字符编码:使用wstring_to_utf8函数将宽字符文件名转换为UTF-8,确保控制台正确显示

五、使用方法

  • 修改代码中的directory变量为目标监控路径。
  • 编译运行(需支持C++11及以上标准)。
  • 在目标目录下执行文件操作(如创建、修改、删除文件),观察控制台输出。

六、注意事项

  • 需要Windows平台和Visual Studio或MinGW等支持Windows API的编译器。
  • 若监控系统目录或频繁变化的目录,建议增大缓冲区大小。
  • 程序需以适当权限运行(例如管理员权限监控受保护目录)。

测试结果/示例

http://www.xdnf.cn/news/6692.html

相关文章:

  • 革新直流计量!安科瑞DJSF1352-D电表:360A免分流直连,精度与空间双突破
  • Linux远程连接服务
  • 1基·2台·3空间·6主体——蓝象智联解码可信数据空间的“数智密码”
  • 5 Celery多节点部署
  • c++,linux,多线程编程详细介绍
  • FC7300 ADC采样理论介绍
  • 宽河道流量监测——阵列雷达波测流系统如何监测河道流量
  • GTS-400 系列运动控制器板卡介绍(三十六)--- 电机到位检测功能
  • Ubuntu 22.04 上安装 Drupal 10并配置 Nginx, mysql 和 php
  • Java 多线程基础:Thread 类核心用法详解
  • E-R图合并时的三种冲突
  • SDT-5土体动力特性测试系统
  • 工具生态构建对比分析
  • 进阶-数据结构部分:1、数据结构入门
  • ASP.NET/IIS New StreamContent(context.Request.InputStream) 不会立即复制整个请求流的内容到内存
  • 什么是本地事务,什么是分布式事务
  • 【MATLAB例程】线性卡尔曼滤波的程序,三维状态量和观测量,较为简单,可用于理解多维KF,附代码下载链接
  • ESP32开发之freeRTOS的任务通知
  • OpenCV CUDA模块中矩阵操作------归一化与变换操作
  • window nvidia-smi命令 Failed to initialize NVML: Unknown Error
  • 【学习笔记】因果推理导论第1课
  • 3D一览通为山东融科MES系统补全车间看图能力
  • 车道线检测----CLRNet
  • Elasticsearch倒排索引核心原理面试题
  • 视频孪生智慧风电场解决方案
  • 【C++/Qt shared_ptr 与 线程池】合作使用案例
  • 模板分享:网络最小费用流
  • css:倒影倾斜效果
  • Jenkins 最佳实践
  • 从数据包到可靠性:UDP/TCP协议的工作原理分析