Как заставить мою программу следить за изменением файлов в C++?


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

5 58

5 ответов:

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

Кросс-Платформенный

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

Windows (Win32)

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

Windows (.NET Framework)

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

OS X

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

Linux

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

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

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

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

рабочий пример для 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 );
}