检测目录文件变化(增、删改)等操作的方法有很多。下面就我使用的方法进行总结如下:
方法一:
使用ReadDirectoryChangesW
优点:
1、可以指定检测目录,缩小检查返回
2、使用简单
缺点:
1、只有unicode班,需要转化
2、需要单开线程,因为该操作是同步阻塞的,在不是overlap情况下
3、异步的overlap的操作方法特别复杂,涉及到完成端口相关信息。
阻塞的情况对我们具体应用其实并没有太大障碍,就是命令线程退出比较麻烦。所以下面就举一个可以正常退出的使用的例子。
举例:
退出时只要将m_ov setevent即可使线程退出。
unsigned MonitorChangeThread()
{
char buf[(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH)*2]={0};
char szPath[MAX_PATH]={0};
char tmp[MAX_PATH]={0}, str1[MAX_PATH]={0}, str2[MAX_PATH]={0};
FILE_NOTIFY_INFORMATION* pNotify=(FILE_NOTIFY_INFORMATION*)buf;
DWORD dwBytesReturned=0;
char *szTDir="d://";
DWORD dwResult = WAIT_OBJECT_0;
HANDLE hFile = CreateFile(szDir,
FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return ERR_MONITOR;
}
while(TRUE)
{
dwResult = WaitForSingleObject(m_eventQuit, g_nTimeOut);
if (WAIT_OBJECT_0 == dwResult)
{
break;
}
if( !::ReadDirectoryChangesW(hFile,
pNotify,
sizeof(buf),
FALSE,
FILE_NOTIFY_CHANGE_FILE_NAME|
FILE_NOTIFY_CHANGE_SIZE|
FILE_NOTIFY_CHANGE_LAST_WRITE|
FILE_NOTIFY_CHANGE_CREATION,
&dwBytesReturned,
&m_ov,
NULL ) )
{
break;
}
if (WaitForSingleObject(m_ov.hEvent, INFINITE) == WAIT_OBJECT_0)
{
dwResult = WaitForSingleObject(m_eventQuit, 0);
if (WAIT_OBJECT_0 == dwResult)
{
break;
}
}
memset(tmp,0,sizeof(tmp));
memset(str1,0,sizeof(str1));
memset(str2,0,sizeof(str2));
WideCharToMultiByte( CP_ACP,0,pNotify->FileName,pNotify->FileNameLength/2,tmp,99,NULL,NULL);
lstrcpy( str1, tmp );
if(pNotify->NextEntryOffset !=0 )
{
PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify+pNotify->NextEntryOffset);
memset( tmp, 0, sizeof(tmp) );
WideCharToMultiByte( CP_ACP,0,p->FileName,p->FileNameLength/2,tmp,99,NULL,NULL);
lstrcpy( str2, tmp );
}
TRACE("c:/ change action %d %s/r/n", pNotify->Action, str1);
switch(pNotify->Action)
{
case FILE_ACTION_ADDED:
case FILE_ACTION_MODIFIED:
{
if (!lstrcmpi(str1,"test.txt"))
{
//to do here
}
break;
}
}
SAFE_CLOSE_HANDLE(hFile);
return 0;
}
//
方法二:
使用SHChangeNotifyRegister
优点:不需开线程,改变以消息的形势出现。
缺点:不能指定检测的目录,程序会将所有的目录改变消息进行捕获,使用不灵活。
改函数需要指定一个窗口,目录改变的内容会以消息的形势出现。在消息响应中处理具体的改变信息
举例:
//注册文件改变消息和窗口 ,具体参数这里不描述,msdn之
SHChangeNotifyEntry ChangeEntry = {0};
m_nChange = SHChangeNotifyRegister(m_hWnd, SHCNRF_ShellLevel, SHCNE_CREATE , WM_FILECHANGE, 1, &ChangeEntry);
if (0 == m_nChange)
{
AfxMessageBox(_T("注册文件改变消息失败"));
}
//窗口过程函数如下:
LONG OnFileChange(WPARAM wParam, LPARAM lParam)
{
typedef struct
{
DWORD dwItem1;
DWORD dwItem2;
}SHNOTIFYSTRUCT;
SHNOTIFYSTRUCT *pNotify = (SHNOTIFYSTRUCT *)wParam;
TCHAR szFileName[MAX_PATH*10], szNewFileName[MAX_PATH*10];
TCHAR szPath[MAX_PATH],szNewPath[MAX_PATH];
SHFILEINFO shFileInfo;
memset(szFileName,0,MAX_PATH*10);
memset(szPath,0,MAX_PATH);
memset(szNewFileName,0,MAX_PATH*10);
memset(szNewPath,0,MAX_PATH);
if(pNotify->dwItem1)
{
SHGetFileInfo((TCHAR*)pNotify->dwItem1,0,&shFileInfo,sizeof(SHFILEINFO),SHGFI_PIDL | SHGFI_DISPLAYNAME);
SHGetPathFromIDList((struct _ITEMIDLIST *)pNotify->dwItem1,szPath);
wsprintf(szFileName,_T("Path:%s Name:%s "), szPath,shFileInfo.szDisplayName);
}
if(pNotify->dwItem2)
{
SHGetFileInfo((TCHAR*)pNotify->dwItem2,0,&shFileInfo,sizeof(SHFILEINFO),SHGFI_PIDL | SHGFI_DISPLAYNAME);
SHGetPathFromIDList((struct _ITEMIDLIST *)pNotify->dwItem2,szNewPath); //LPCITEMIDLIST
wsprintf(szNewFileName,_T("Path:%s Name:%s "), szNewPath,shFileInfo.szDisplayName);
//MessageBox(szNewFileName);
}
switch(lParam)
{
case SHCNE_RENAMEITEM: //改名
break;
case SHCNE_CREATE: //创建
break;
case SHCNE_DELETE: //删除
break;
case SHCNE_MKDIR : //创建目录
break;
case SHCNE_RMDIR : //移除目录
break;
case SHCNE_RENAMEFOLDER:
break;
case SHCNE_ATTRIBUTES : //改变
break;
}
return 0;
}