【发布时间】:2010-10-30 04:29:42
【问题描述】:
有很多程序,例如 Visual Studio,可以检测外部程序何时修改文件,然后在用户需要时重新加载文件。有没有一种相对简单的方法可以在 C++ 中做这种事情(不一定必须独立于平台)?
【问题讨论】:
标签: c++ file-io filesystems monitoring fsevents
有很多程序,例如 Visual Studio,可以检测外部程序何时修改文件,然后在用户需要时重新加载文件。有没有一种相对简单的方法可以在 C++ 中做这种事情(不一定必须独立于平台)?
【问题讨论】:
标签: c++ file-io filesystems monitoring fsevents
根据平台的不同,有几种方法可以做到这一点。我会从以下选项中进行选择:
奇趣科技的 Qt 有一个名为 QFileSystemWatcher 的对象,它允许您监视文件和目录。我确信还有其他跨平台框架也可以为您提供这种功能,但根据我的经验,这个框架运行得相当好。
有一个名为FindFirstChangeNotification 的 Win32 api 可以完成这项工作。有一篇不错的文章,其中一个名为 How to get a notification if change occurs in a specified directory 的 api 小包装类将帮助您入门。
如果您可以在 .NET Framework 中使用 C++/CLI,那么 System.IO.FileSystemWatcher 是您的首选课程。微软有一篇很好的文章 how to monitor file system changes 使用这个类。
FSEvents API 是 OS X 10.5 的新 API,功能非常全面。
使用 inotify,正如 Alex 在他的回答中提到的那样。
【讨论】:
如果您不需要独立于平台,那么在 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 );
}
【讨论】:
为 libuv 添加一个答案(尽管它是用 C 编写的),它通过系统特定的 API 支持 Windows 和 Linux:
Linux 上的 inotify,Darwin 上的 FSEvents,BSD 上的 kqueue, Windows 上的 ReadDirectoryChangesW,Solaris 上的事件端口,不受支持 在 Cygwin 上
您可以查看文档here,注意文档说通知相关的API不是很一致。
【讨论】:
libuv 可以监视同一个文件系统中的文件移动吗?
move事件的信息。