对指定的一个目录进行监控,当该目录中有文件发生改变,并通知处理。 Windows提供了对文件和目录监控的系统服务,并且为应用程序提供了两个API函数,它们分别是:FindFirstChangeNotification和ReadDirectoryChangesW。由于通过FindFirstChangeNotification函数只能监控到某一目录下有文件发生改变,而不能监控到具体是哪一文件发生改变,所以本人选用ReadDirectoryChangesW函数。该函数的定义为:
第一个参数是要监控目录的句柄,可以通过指定目录名,利用CreateFile函数的返回值获得。用户代码通过第二个和第三个参数来告知操作系统该把目录变化通知放在首地址为返回信息指针, 一块内存长度区域当中的。但是该内存又是怎样组织的呢?操作系统是把他们放在FILE_NOTIFY_INFORMATION这个结构里面的:
这是一个自定义结构,第一个字段存储了要获得下一个记录需要跳过多少字节数,如果它的值为0,就表示本记录已经是最后一条记录了。该字段其实也可以看作是一个指向下一条记录的指针。第二个字段的含义是:本次通知了哪种类型的目录变化。第三个字段表示的是变化的文件名称的长度。第四个字段是一个存放变化的文件名称的Unicode字符数组的首地址。
另外一个与本系统有关的参数是类型过滤器。它是目录变化通知过滤器。要监控文件名发生变化,此参数应设为FILE_NOTIFY_CHANGE_FILE_NAME;文件被非法改写为FILE_NOTIFY_CHANGE_LAST_WRITE等等。根据过滤器的设置,ReadDirectoryChangesW函数可以监控文件名改变、文件属性改变、文件大小改变、文件内容被改写、文件被删除等多种类型的变化。
利用ReadDirectoryChangesW函数实现对一个目录进行监控的。具体的做法是:首先使用CreateFile获取要监控目录的句柄;然后在一个判断循环里面调用ReadDirectoryChangesW,并且把自己分配的用来存放目录变化通知的内存首地址、内存长度、目录句柄传给该函数。用户代码在该函数的调用中进行同步等待。当目录中有文件发生改变,控制函数把目录变化通知存放在指定的内存区域内,并把发生改变的文件名、文件所在目录和改变通知处理。
利用此API写的文件目录事件监视器:
CfgdsgDlg * dlg = (CfgdsgDlg*)lparam;
HANDLE hDir;
char notify[1024];
DWORD cbBytes,i;
char AnsiChar[3];
wchar_t UnicodeChar[2];
CString path;
FILE_NOTIFY_INFORMATION *pnotify=(FILE_NOTIFY_INFORMATION *)notify;
FILE_NOTIFY_INFORMATION *tmp;
GetCurrentDirectory(MAX_PATH,path.GetBuffer(MAX_PATH+1));
hDir = CreateFile( path, FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS |
FILE_FLAG_OVERLAPPED, NULL);
if (hDir == INVALID_HANDLE_VALUE)
{
dlg->m_edit.ReplaceSel("hDir:INVALID_HANDLE_VALUE\r\n");
return 0;
}
while (TRUE)
{
if(ReadDirectoryChangesW(hDir, ¬ify, sizeof(notify),
FALSE, FILE_NOTIFY_CHANGE_FILE_NAME| FILE_NOTIFY_CHANGE_LAST_WRITE,
&cbBytes, NULL, NULL))
{
tmp = pnotify;
switch(tmp->Action)
{
case FILE_ACTION_ADDED:
dlg->m_edit.ReplaceSel("Directory/File added (添加文件)- \r\n");
break;
case FILE_ACTION_REMOVED:
dlg->m_edit.ReplaceSel("Directory/File removed (删除文件)- \r\n");
break;
case FILE_ACTION_MODIFIED:
dlg->m_edit.ReplaceSel("Directory/File modified (修改文件内容)- \r\n");
break;
case FILE_ACTION_RENAMED_OLD_NAME:
dlg->m_edit.ReplaceSel("Directory/File old name (修改文件名字)- \r\n");
break;
case FILE_ACTION_RENAMED_NEW_NAME:
dlg->m_edit.ReplaceSel("Directory/File new name - \r\n");
break;
default:
break;
}
}
}
FILE_NOTIFY_INFORMATION //可以确定是那个文件进行的修改
typedef struct _FILE_NOTIFY_INFORMATION {
DWORD NextEntryOffset;
DWORD Action;//动作
DWORD FileNameLength;//文件名字的长度
WCHAR FileName[1];//文件名字
} FILE_NOTIFY_INFORMATION,
*PFILE_NOTIFY_INFORMATION;
ReadDirectoryChangesW 返回类型(见MSDN)
Value | Meaning |
---|---|
FILE_ACTION_ADDED | The file was added to the directory. |
FILE_ACTION_REMOVED | The file was removed from the directory. |
FILE_ACTION_MODIFIED | The file was modified. This can be a change in the time stamp or attributes. |
FILE_ACTION_RENAMED_OLD_NAME | The file was renamed and this is the old name. |
FILE_ACTION_RENAMED_NEW_NAME | The file was renamed and this is the new name. |
不足的地方:
只能检测到指定目录和下一级目录,超过目录级数,该函数检测不到。