Windows 2000 引入了两个新接口,FindFirstChangeNotification 和 ReadDirectoryChangesW 。 FindFirstChangeNotification 很容易使用,但没有给出变更文件的信息。即便如此,这个函数对某些应用程序还是很有用的,比如传真服务和 SMTP 服务可以通过拖拽一个文件到一个目录来接受任务队列。ReadDirectoryChangesW 会给出变更的内容和方式, 不过相对的,在使用上也更复杂一些。
1.FindFirstChangeNotification()函数
功能:创建一个改变通知句柄,并设置通知条件,即发生某种修改时,该通知句柄将被促发生效。该函数仅仅负责对文件修改作出通知,并不记录和反馈修改信息。
返回值:成功时返回指向改变通知的句柄,失败时返回INVALID_HANDLE_VALUE,可以用GetLastError()函数得到。
例子:部分代码如下
//使用FindFirstChangeNotification和FindNextChangeNotification实现文件监控
CString Monitor1()
{
HANDLE hEvent;//监控句柄
//char* path[MAX_PATH+1] ;//监控目录
static int m_nCount = 0; //当前操作的序号
CString str;
//GetCurrentDirectory(MAX_PATH, (LPWSTR)path);
hEvent = FindFirstChangeNotification("E:\",TRUE,FILE_NOTIFY_CHANGE_FILE_NAME| //查看指定目录下任何文件名的改变
FILE_NOTIFY_CHANGE_DIR_NAME| //查看指定目录下任何目录名的改变
FILE_NOTIFY_CHANGE_SIZE| //查看指定文件大小的改变
FILE_NOTIFY_CHANGE_ATTRIBUTES);//查看指定目录下文件属性的改变
if (hEvent == INVALID_HANDLE_VALUE)
{
//ExitProcess(GetLastError());//获取错误
//return;
str.Format("%s %s", "error", GetLastError());
return str;
}
//while (TRUE)//循环监控
{
DWORD nobj;
nobj= WaitForSingleObject(hEvent,INFINITE);//等待,文件夹任何动作,都返回0,顾不能知道具体动作和具体哪个文件发生了变化
if (nobj)
{
;
}
m_nCount++;
str.Format("%d %s", m_nCount, "文件发生了变化!");
printf("文件发生了变化
");
//继续监控
if(FALSE==FindNextChangeNotification(hEvent))
{
//ExitProcess(GetLastError());
//return;
str.Format("%s %s", "error", GetLastError());
return str;
}
}
return str;
}
2.ReadDirectoryChangesW()函数
功能:监控文件修改,并记录文件修改的相关信息,如修改的文件名,何种类型的修改等。
返回值:如果函数成功,返回值就是非0。对于同步调用,这意味着操作成功,对于异步调用,这意味着操作成功地排队。如果函数失败,返回值是0。如果操作目录或文件系统不支持这个操作,函数将返回ERROR_INVALID_FUNCTION,可以使用GetLastError()函数获取。
例子:部分代码如下
//使用ReadDirectoryChangesW实现文件监控
CString Monitor2()
{
DWORD cbBytes;
char cFileName[1024]; //设置文件名
char cNewFileName[1024]; //设置文件重命名后的名字
char cNotify[1024];
static int m_nCount = 0; //当前操作的序号
TCHAR *pDirectory = "E:\";//m_strAddress.GetBuffer(m_strAddress.GetLength());
CString str;
HANDLE dirHandle;
dirHandle = CreateFile(
pDirectory,
GENERIC_READ | GENERIC_WRITE | FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
memset(cNotify, 0, strlen(cNotify));
FILE_NOTIFY_INFORMATION *pNotify = (FILE_NOTIFY_INFORMATION*)cNotify;
//若网络重定向或目标文件系统不支持该操作,函数失败,同时调用GetLastError()返回ERROR_INVALID_FUNCTION
if(dirHandle == INVALID_HANDLE_VALUE)
{
str.Format("%s %s", "error", GetLastError());
return str;
}
if(ReadDirectoryChangesW(
dirHandle,
&cNotify,
1024,
true,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME
//| FILE_NOTIFY_CHANGE_CREATION
//| FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_SIZE,
&cbBytes,NULL,NULL))
{
//转换文件名为多字节字符串
if(pNotify->FileName)
{
memset(cFileName, 0, strlen(cFileName));
WideCharToMultiByte(CP_ACP, 0, pNotify->FileName, pNotify->FileNameLength/2, cFileName, 99, NULL, NULL);
}
//获取重命名的文件名
if(pNotify->NextEntryOffset != 0 && (pNotify->FileNameLength > 0 && pNotify->FileNameLength < MAX_PATH))
{
PFILE_NOTIFY_INFORMATION p = (PFILE_NOTIFY_INFORMATION)((char*)pNotify + pNotify->NextEntryOffset);
memset(cNewFileName, 0, sizeof(cNewFileName));
WideCharToMultiByte(CP_ACP, 0, p->FileName, p->FileNameLength/2, cNewFileName, 99, NULL, NULL);
}
//设置类型过滤器,监听文件创建、更改、删除、重命名等
switch(pNotify->Action)
{
case FILE_ACTION_ADDED:
m_nCount++;
str.Format("%d %s %s", m_nCount, "file add:", cFileName);
//AfxMessageBox(str);
break;
case FILE_ACTION_MODIFIED:
m_nCount++;
str.Format("%d %s %s", m_nCount, "file modified:", cFileName);
//AfxMessageBox(str);
break;
case FILE_ACTION_REMOVED:
m_nCount++;
str.Format("%d %s %s", m_nCount, "file removed:", cFileName);
//AfxMessageBox(str);
break;
case FILE_ACTION_RENAMED_OLD_NAME:
m_nCount++;
str.Format("%d %s %s %s %s", m_nCount, "file renamed:", cFileName, "->", cNewFileName);
//AfxMessageBox(str);
break;
default:
//MessageBox("unknow command!");
break;
}
CloseHandle(dirHandle);
}
return str;
}