在使用ReadDirectoryChanges的时候发现了一个问题,在向监控的文件夹添加了大量的文件时,出现了文件漏检的问题。我使用的是从网上找到的教程,起初也不是很清楚,认为是程序没能响应大量的操作。后来发现问题出在文件名的获取上。
下面是我的核心代码部分:
m_FileCnt=0;
HANDLE dirHandle = CreateFile(
dir,
GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if(dirHandle == INVALID_HANDLE_VALUE)
{
output_info_str="error"+GetLastError();
::PostMessage(pMain->GetSafeHwnd(),WM_UPDATE_BUILD_WINDOW,0,(LPARAM)&output_info_str);
}
while(m_ifRunMonitor&&(!m_ifForceStop))
{
memset(notify,0,strlen(notify));
FILE_NOTIFY_INFORMATION *pnotify = (FILE_NOTIFY_INFORMATION*)notify;
if(ReadDirectoryChangesW(
dirHandle, //指向监控目录的句柄
notify, //存储修改信息的首地址
sizeof(notify), //存储修改信息的空间大小
TRUE, //是否监控子目录
FILE_NOTIFY_CHANGE_CREATION||FILE_NOTIFY_CHANGE_LAST_WRITE||FILE_NOTIFY_CHANGE_SIZE,
&cbBytes, //该函数返回信息的字节数,也就是存到lpBuffer中的内容的字节数
NULL, //一个指向OVERLAPPED结构的指针,在同步调用时提供数据供使用,否则就为NULL
NULL)) //当操作结束或被取消或者线程进入等待状态时的一个指向将被调用操作的指针
{
if(pnotify->Action==FILE_ACTION_ADDED)
{
PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pnotify);
while(!m_ifForceStop)
{
if (p->FileNameLength>0 && p->FileNameLength<MAX_PATH)
{
memset(file_name,0,sizeof(file_name));
WideCharToMultiByte(CP_ACP,0,p->FileName,p->FileNameLength/2,file_name,256,NULL,NULL );
if (strlen(file_name)==0)
{
break;
}
m_FileNamelist[m_FileCnt%MY_VECTOR_SIZE]=file_name;
m_FileCnt++;
if(p->NextEntryOffset !=0)
{
PFILE_NOTIFY_INFORMATION p_nxt = (PFILE_NOTIFY_INFORMATION)((char*)p+p->NextEntryOffset);
p=p_nxt;
}
}
}
}
}
}
这里和之前我参考的代码最不一样的地方就是添加了指向下一个节点的指针。实际上获取到的文件名是一个和链表类似的数据结构PFILE_NOTIFY_INFORMATION,包含了一个指向下一个节点的偏移量,因此通过不断的去增加偏移量,就可以获取到下一个节点存储的文件名;当偏移量为0时,说明本次检索到的文件列表已经到头了。利用while循环再次检索,就实现了文件夹的持续监控。
程序是直接从我工程里面摘出来的,字符使用的是多字节编码,如果直接运行不一定能跑通,而且我的程序因为应用的场景的原因,只监控添加的文件,这个函数还可以检测重命名、修改等等各类情况,有兴趣的话可以查阅一下这个函数的定义。