web-dev-qa-db-fra.com

Comment faire en sorte que mon programme surveille la modification des fichiers en C ++?

Il existe de nombreux programmes, Visual Studio par exemple, qui peuvent détecter lorsqu'un programme externe modifie un fichier, puis recharger le fichier si l'utilisateur le souhaite. Existe-t-il un moyen relativement facile de faire ce genre de chose en C++ (ne doit pas nécessairement être indépendant de la plate-forme)?

65
Alex

Il existe plusieurs façons de procéder en fonction de la plate-forme. Je choisirais parmi les choix suivants:

Plateforme croisée

Le Qt de Trolltech a un objet appelé QFileSystemWatcher qui vous permet de surveiller les fichiers et les répertoires. Je suis sûr qu'il existe d'autres cadres multiplateformes qui vous offrent également ce type de capacité, mais celui-ci fonctionne assez bien d'après mon expérience.

Windows (Win32)

Il existe une API Win32 appelée FindFirstChangeNotification qui fait le travail. Il y a un article sympa sur lequel une petite classe wrapper pour l'api s'appelle Comment obtenir une notification si un changement se produit dans un répertoire spécifié qui vous aidera à démarrer.

Windows (.NET Framework)

Si vous êtes d'accord avec C++/CLI avec le .NET Framework, alors System.IO.FileSystemWatcher est votre classe de choix. Microsoft a un bel article sur comment surveiller les modifications du système de fichiers en utilisant cette classe.

OS X

L'API FSEvents est nouvelle pour OS X 10.5 et très complète.

Linux

Utilisez inotify comme Alex l'a mentionné dans sa réponse.

91
Nick Haddad

Si vous n'avez pas besoin d'être indépendant de la plate-forme, une approche sous Linux qui peut être moins chargée en machine que "polling" (vérification périodique) est inotify, voir http: // fr .wikipedia.org/wiki/Inotify et ses nombreux liens par exemple. Pour Windows, voir http://msdn.Microsoft.com/en-us/library/aa365261 (VS.85) .aspx .

17
Alex Martelli

SimpleFileWatcher pourrait être ce que vous recherchez. Mais bien sûr, c'est une dépendance externe - ce n'est peut-être pas une option pour vous.

8
Martin Gerhardy

Bien sûr, tout comme VC++. Vous obtenez la dernière heure modifiée lorsque vous ouvrez le fichier et vous le vérifiez périodiquement pendant que le fichier est ouvert. Si last_mod_time> saved_mod_time, c'est arrivé.

5
Charlie Martin

Un exemple pratique pour 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
Ataginsky