Как мне заставить мою программу следить за изменениями файлов в C ++? - PullRequest
60 голосов
/ 31 мая 2009

Существует множество программ, например, Visual Studio, которые могут определять, когда внешняя программа изменяет файл, а затем перезагружать файл, если пользователь хочет выбрать. Есть ли относительно простой способ сделать что-то подобное в C ++ (не обязательно должен быть независимым от платформы)?

Ответы [ 5 ]

88 голосов
/ 31 мая 2009

Есть несколько способов сделать это в зависимости от платформы. Я бы выбрал из следующих вариантов:

Кросс-платформа

В Qt Trolltech есть объект с именем QFileSystemWatcher , который позволяет вам отслеживать файлы и каталоги. Я уверен, что есть и другие кроссплатформенные фреймворки, которые также предоставляют вам такую ​​возможность, но, по моему опыту, эта работает довольно хорошо.

Windows (Win32)

Существует Win32 API под названием FindFirstChangeNotification , который выполняет эту работу. Есть хорошая статья, которая представляет собой небольшой класс-обертку для API под названием Как получить уведомление, если в указанном каталоге произойдет изменение, которое поможет вам начать работу.

Windows (.NET Framework)

Если вы хорошо используете C ++ / CLI с .NET Framework, тогда System.IO.FileSystemWatcher - ваш класс выбора. У Microsoft есть хорошая статья на как отслеживать изменения файловой системы с помощью этого класса.

OS X

API FSEvents является новым для OS X 10.5 и очень полнофункциональным.

Linux

Используйте inotify , как Алекс упомянул в своем ответе.

17 голосов
/ 31 мая 2009

Если вам не нужно быть независимым от платформы, подход в Linux, который может быть менее загружен машиной, чем «опрос» (периодически проверяется), составляет inotify, см. http://en.wikipedia.org/wiki/Inotify и многие ссылки с него например. Для Windows см. http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx.

8 голосов
/ 07 апреля 2015

SimpleFileWatcher может быть то, что вы ищете. Но, конечно, это внешняя зависимость - возможно, это не вариант для вас.

5 голосов
/ 04 марта 2015

Рабочий пример для WinCE

void FileInfoHelper::WatchFileChanges( TCHAR *ptcFileBaseDir, TCHAR *ptcFileName ){
static int iCount = 0;
DWORD dwWaitStatus; 
HANDLE dwChangeHandles; 

if( ! ptcFileBaseDir || ! ptcFileName ) return;

wstring wszFileNameToWatch = ptcFileName;

dwChangeHandles = FindFirstChangeNotification(
    ptcFileBaseDir,
    FALSE,
    FILE_NOTIFY_CHANGE_FILE_NAME |
    FILE_NOTIFY_CHANGE_DIR_NAME |
    FILE_NOTIFY_CHANGE_ATTRIBUTES |
    FILE_NOTIFY_CHANGE_SIZE |
    FILE_NOTIFY_CHANGE_LAST_WRITE |
    FILE_NOTIFY_CHANGE_LAST_ACCESS |
    FILE_NOTIFY_CHANGE_CREATION |
    FILE_NOTIFY_CHANGE_SECURITY |
    FILE_NOTIFY_CHANGE_CEGETINFO
    );

if (dwChangeHandles == INVALID_HANDLE_VALUE) 
{
    printf("\n ERROR: FindFirstChangeNotification function failed [%d].\n", GetLastError());
    return;
}

while (TRUE) 
{ 
    // Wait for notification.
    printf("\n\n[%d] Waiting for notification...\n", iCount);
    iCount++;

    dwWaitStatus = WaitForSingleObject(dwChangeHandles, INFINITE); 
    switch (dwWaitStatus) 
    { 
        case WAIT_OBJECT_0: 

            printf( "Change detected\n" );

            DWORD iBytesReturned, iBytesAvaible;
            if( CeGetFileNotificationInfo( dwChangeHandles, 0, NULL, 0, &iBytesReturned, &iBytesAvaible) != 0 ) 
            {
                std::vector< BYTE > vecBuffer( iBytesAvaible );

                if( CeGetFileNotificationInfo( dwChangeHandles, 0, &vecBuffer.front(), vecBuffer.size(), &iBytesReturned, &iBytesAvaible) != 0 ) {
                    BYTE* p_bCurrent = &vecBuffer.front();
                    PFILE_NOTIFY_INFORMATION info = NULL;

                    do {
                        info = reinterpret_cast<PFILE_NOTIFY_INFORMATION>( p_bCurrent );
                        p_bCurrent += info->NextEntryOffset;

                        if( wszFileNameToWatch.compare( info->FileName ) == 0 )
                        {
                            wcout << "\n\t[" << info->FileName << "]: 0x" << ::hex << info->Action;

                            switch(info->Action) {
                                case FILE_ACTION_ADDED:
                                    break;
                                case FILE_ACTION_MODIFIED:
                                    break;
                                case FILE_ACTION_REMOVED:
                                    break;
                                case FILE_ACTION_RENAMED_NEW_NAME:
                                    break;
                                case FILE_ACTION_RENAMED_OLD_NAME:
                                    break;
                            }
                        }
                    }while (info->NextEntryOffset != 0);
                }
            }

            if ( FindNextChangeNotification( dwChangeHandles ) == FALSE )
            {
                printf("\n ERROR: FindNextChangeNotification function failed [%d].\n", GetLastError());
                return;
            }

            break; 

        case WAIT_TIMEOUT:
            printf("\nNo changes in the timeout period.\n");
            break;

        default: 
            printf("\n ERROR: Unhandled dwWaitStatus [%d].\n", GetLastError());
            return;
            break;
    }
}

FindCloseChangeNotification( dwChangeHandles );
}
5 голосов
/ 31 мая 2009

Конечно, так же, как VC ++. Когда вы открываете файл, вы получаете время последнего изменения и периодически проверяете его, пока у вас открыт файл. Если last_mod_time> save_mod_time, это произошло.

...