디렉터리 변경 알림 가져오기

애플리케이션은 변경 알림을 사용하여 디렉터리 및 해당 하위 디렉터리의 콘텐츠를 모니터링할 수 있습니다. 변경 알림을 기다리는 것은 디렉터리 및 필요한 경우 해당 하위 디렉터리에 대한 읽기 작업이 보류 중인 것과 유사합니다. 감시 중인 디렉터리 내에서 변경 사항이 있으면 읽기 작업이 완료됩니다. 예를 들어 애플리케이션은 모니터링한 디렉터리 내에서 파일 이름이 변경될 때마다 함수를 사용하여 디렉터리 목록을 업데이트할 수 있습니다.

애플리케이션은 FindFirstChangeNotification 함수를 사용하여 변경 알림을 트리거하는 일련의 조건을 지정할 수 있습니다. 조건에는 파일 이름, 디렉터리 이름, 특성, 파일 크기, 마지막 쓰기 시간, 보안 등의 변경이 포함됩니다. 또한 이 함수는 대기 함수를 사용하여 대기할 수 있는 핸들을 반환합니다. 대기 조건이 충족되면 FindNextChangeNotification을 사용하여 후속 변경에서 대기하는 알림 핸들을 제공할 수 있습니다. 그러나 이러한 함수는 대기 조건을 충족한 실제 변경을 나타내지 않습니다.

FindCloseChangeNotification을 사용하여 알림 핸들을 닫습니다.

알림의 일부로 특정 변경에 대한 정보를 검색하려면 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);
}