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)?
Il existe plusieurs façons de procéder en fonction de la plate-forme. Je choisirais parmi les choix suivants:
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.
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.
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.
L'API FSEvents est nouvelle pour OS X 10.5 et très complète.
Utilisez inotify comme Alex l'a mentionné dans sa réponse.
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 .
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.
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é.
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 );
}