Поделиться через


Получение уведомлений об изменении каталога

Приложение может отслеживать содержимое каталога и его подкаталогов с помощью уведомлений об изменениях. Ожидание уведомления об изменении аналогично выполнению операции чтения в каталоге и при необходимости его подкаталогов. Когда в отслеживаемом каталоге происходят изменения, операция чтения завершается. Например, приложение может использовать эти функции для обновления списка каталогов всякий раз, когда имя файла в отслеживаемом каталоге изменяется.

Приложение может указать набор условий, которые активируют уведомление об изменении с помощью функции FindFirstChangeNotification. Условия включают изменения в имена файлов, имена каталогов, атрибуты, размер файла, время последней записи и безопасность. Эта функция также возвращает дескриптор , ожидание которого возможно с помощью функций ожидания. Если условие ожидания выполнено, можно использовать функцию FindNextChangeNotification для предоставления дескриптора уведомлений, который будет ожидать последующих изменений. Однако эти функции не указывают фактическое изменение, удовлетворяющее условию ожидания.

Используйте FindCloseChangeNotification, чтобы закрыть дескриптор уведомлений.

Чтобы получить сведения о конкретном изменении в рамках уведомления, используйте функцию ReadDirectoryChangesW . Эта функция также позволяет предоставить завершающую процедуру.

Примечание.

Функции FindFirstChangeNotification и ReadDirectoryChangesW являются взаимоисключающими. Вы должны использовать один или другой, но не оба.

Чтобы отслеживать изменения на томе, см. журналы изменений.

В следующем примере отслеживается дерево каталогов на предмет изменений имён каталогов. Он также отслеживает каталог для изменения имени файла. В этом примере функция FindFirstChangeNotification используется для создания двух дескрипторов уведомлений, а функция WaitForMultipleObjects — чтобы ожидать их. Каждый раз, когда каталог создается или удаляется в дереве, пример должен обновлять весь дерево каталогов. Каждый раз, когда файл создается или удаляется в каталоге, пример должен обновить каталог.

 

#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);
}