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

StackOverflow https://stackoverflow.com/questions/931093

Вопрос

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

Это было полезно?

Решение

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

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

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

Windows (Win32)

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

Windows (.NET Framework)

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

Операционная система X

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

Linux

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

Другие советы

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

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

Конечно, точно так же, как это делает 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 );
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top