Как заставить мою программу следить за изменением файлов в C++?
есть много программ, например Visual Studio, которые могут обнаруживать, когда внешняя программа изменяет файл, а затем перезагружает файл, если пользователь хочет выбрать. Есть ли относительно простой способ сделать это в C++ (не обязательно должен быть независимым от платформы)?
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 ); }