取得目錄變更通知
應用程式可以使用變更通知來監視目錄及其子目錄的內容。 等候變更通知類似於對目錄進行擱置的讀取作業,並視需要等候其子目錄。 當目錄內發生變更時,讀取作業就會完成。 例如,每當受監視目錄內的檔名變更時,應用程式就可以使用這些函式來更新目錄清單。
應用程式可以使用 FindFirstChangeNotification 函式來指定觸發變更通知的一組條件。 這些條件包括檔名、目錄名稱、屬性、檔案大小、上次寫入時間和安全性的變更。 此函式也會傳回可以使用等候函式等候的句柄。 如果滿足等候條件, 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);
}