获取目录更改通知
应用程序可以使用更改通知来监视目录及其子目录的内容。 等待更改通知类似于对目录以及必要时对其子目录挂起读取操作。 监视的目录中的内容发生更改时,读取操作将完成。 例如,每当被监视目录内的文件名发生更改时,应用程序都可以使用这些函数更新目录列表。
应用程序可以使用 FindFirstChangeNotification 函数指定触发更改通知的一组条件。 条件包括对文件名、目录名称、属性、文件大小、上次写入时间和安全性的更改。 此函数还会返回可以使用 wait 函数等待的句柄。 如果满足了等待条件,则 FindNextChangeNotification 可用于提供通知句柄来等待后续更改。 但是,这些函数并不指示满足等待条件的实际更改。
使用 FindCloseChangeNotification 关闭通知句柄。
若要在通知中检索有关特定更改的信息,请使用 ReadDirectoryChangesW 函数。 此函数还允许你提供完成例程。
注意
FindFirstChangeNotification 和 ReadDirectoryChangesW 函数互斥。 你应该使用一种方法或另一种方法,但不能二者都用。
若要跟踪卷上的更改,请参阅更改日记帐。
以下示例监视目录树中的目录名称更改。 它还监视目录中的文件名更改。 该示例使用 FindFirstChangeNotification 函数来创建两个通知句柄,使用 WaitForMultipleObjects 函数来等待这些句柄。 每当在树中创建或删除目录时,该示例都应更新整个目录树。 每当在目录中创建或删除文件时,该示例都应刷新目录。
注意
此简单示例使用 ExitProcess 函数进行终止和清理,但更复杂的应用程序始终应酌情使用适当的资源管理,例如 FindCloseChangeNotification。
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
void RefreshDirectory(LPTSTR);
void RefreshTree(LPTSTR);
void WatchDirectory(LPTSTR);
void _tmain(int argc, TCHAR *argv[])
{
if(argc != 2)
{
_tprintf(TEXT("Usage: %s <dir>\n"), argv[0]);
return;
}
WatchDirectory(argv[1]);
}
void WatchDirectory(LPTSTR lpDir)
{
DWORD dwWaitStatus;
HANDLE dwChangeHandles[2];
TCHAR lpDrive[4];
TCHAR lpFile[_MAX_FNAME];
TCHAR lpExt[_MAX_EXT];
_tsplitpath_s(lpDir, lpDrive, 4, NULL, 0, lpFile, _MAX_FNAME, lpExt, _MAX_EXT);
lpDrive[2] = (TCHAR)'\\';
lpDrive[3] = (TCHAR)'\0';
// Watch the directory for file creation and deletion.
dwChangeHandles[0] = FindFirstChangeNotification(
lpDir, // directory to watch
FALSE, // do not watch subtree
FILE_NOTIFY_CHANGE_FILE_NAME); // watch file name changes
if (dwChangeHandles[0] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Watch the subtree for directory creation and deletion.
dwChangeHandles[1] = FindFirstChangeNotification(
lpDrive, // directory to watch
TRUE, // watch the subtree
FILE_NOTIFY_CHANGE_DIR_NAME); // watch dir name changes
if (dwChangeHandles[1] == INVALID_HANDLE_VALUE)
{
printf("\n ERROR: FindFirstChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
// Make a final validation check on our handles.
if ((dwChangeHandles[0] == NULL) || (dwChangeHandles[1] == NULL))
{
printf("\n ERROR: Unexpected NULL from FindFirstChangeNotification.\n");
ExitProcess(GetLastError());
}
// Change notification is set. Now wait on both notification
// handles and refresh accordingly.
while (TRUE)
{
// Wait for notification.
printf("\nWaiting for notification...\n");
dwWaitStatus = WaitForMultipleObjects(2, dwChangeHandles,
FALSE, INFINITE);
switch (dwWaitStatus)
{
case WAIT_OBJECT_0:
// A file was created, renamed, or deleted in the directory.
// Refresh this directory and restart the notification.
RefreshDirectory(lpDir);
if ( FindNextChangeNotification(dwChangeHandles[0]) == FALSE )
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_OBJECT_0 + 1:
// A directory was created, renamed, or deleted.
// Refresh the tree and restart the notification.
RefreshTree(lpDrive);
if (FindNextChangeNotification(dwChangeHandles[1]) == FALSE )
{
printf("\n ERROR: FindNextChangeNotification function failed.\n");
ExitProcess(GetLastError());
}
break;
case WAIT_TIMEOUT:
// A timeout occurred, this would happen if some value other
// than INFINITE is used in the Wait call and no changes occur.
// In a single-threaded environment you might not want an
// INFINITE wait.
printf("\nNo changes in the timeout period.\n");
break;
default:
printf("\n ERROR: Unhandled dwWaitStatus.\n");
ExitProcess(GetLastError());
break;
}
}
}
void RefreshDirectory(LPTSTR lpDir)
{
// This is where you might place code to refresh your
// directory listing, but not the subtree because it
// would not be necessary.
_tprintf(TEXT("Directory (%s) changed.\n"), lpDir);
}
void RefreshTree(LPTSTR lpDrive)
{
// This is where you might place code to refresh your
// directory listing, including the subtree.
_tprintf(TEXT("Directory tree (%s) changed.\n"), lpDrive);
}