如何让我的程序监视 C++ 中的文件修改?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/931093/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:02:02  来源:igfitidea点击:

How do I make my program watch for file modification in C++?

c++file-iofilesystemsmonitoringfsevents

提问by Alex

There are a lot of programs, Visual Studio for instance, that can detect when an outside program modifies a file and then reload the file if the user wants chooses. Is there a relatively easy way to do this sort of thing in C++ (doesn't necessarily have to be platform independent)?

有很多程序,例如 Visual Studio,可以检测外部程序何时修改文件,然后如果用户愿意选择重新加载文件。在 C++ 中是否有一种相对简单的方法来做这种事情(不一定要独立于平台)?

回答by Nick Haddad

There are several ways to do this depending on the platform. I would choose from the following choices:

根据平台的不同,有几种方法可以做到这一点。我会从以下选项中进行选择:

Cross Platform

跨平台

Trolltech's Qt has an object called QFileSystemWatcherwhich allows you to monitor files and directories. I'm sure there are other cross platform frameworks that give you this sort of capability too, but this one works fairly well in my experience.

Trolltech 的 Qt 有一个名为QFileSystemWatcher的对象,它允许您监视文件和目录。我敢肯定还有其他跨平台框架也可以为您提供这种功能,但根据我的经验,这个框架效果很好。

Windows (Win32)

视窗 (Win32)

There is a Win32 api called FindFirstChangeNotificationwhich does the job. There is a nice article which a small wrapper class for the api called How to get a notification if change occurs in a specified directorywhich will get you started.

有一个名为FindFirstChangeNotification的 Win32 api可以完成这项工作。有一篇很好的文章,其中有一个名为“如果指定目录中发生更改时如何获取通知”的 api 小包装类,它将帮助您入门。

Windows (.NET Framework)

Windows(.NET 框架)

If you are ok using C++/CLI with the .NET Framework then System.IO.FileSystemWatcheris your class of choice. Microsoft has a nice article on how to monitor file system changesusing this class.

如果您可以在 .NET Framework 中使用 C++/CLI,那么 System.IO.FileSystemWatcher是您的首选。Microsoft 有一篇关于如何使用此类监视文件系统更改的好文章 。

OS X

操作系统

The FSEventsAPI is new for OS X 10.5 and very full-featured.

FSEventsAPI是新的OS X 10.5和非常功能全面。

Linux

Linux

Use inotifyas Alex mentioned in his answer.

使用亚历克斯在他的回答中提到的inotify

回答by Alex Martelli

If you don't need to be platform-independent, an approach on Linux that may be less of a machine load than "polling" (checking periodically) is inotify, see http://en.wikipedia.org/wiki/Inotifyand the many links from it for example. For Windows, see http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx.

如果您不需要独立于平台,Linux 上可能比“轮询”(定期检查)机器负载更少的方法是inotify,请参阅http://en.wikipedia.org/wiki/Inotify和例如,来自它的许多链接。对于 Windows,请参阅http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx

回答by Martin Gerhardy

SimpleFileWatchermight be what you are looking for. But of course it is an external dependency - maybe that is no option for you.

SimpleFileWatcher可能正是您要找的。但当然它是一种外部依赖——也许这对你来说是没有选择的。

回答by Charlie Martin

Sure, just like VC++ does. You get the last modified time when you open the file, and you periodically check it while you have the file open. If last_mod_time > saved_mod_time, it happened.

当然,就像 VC++ 一样。打开文件时,您会获得上次修改时间,并在打开文件时定期检查它。如果 last_mod_time > saved_mod_time,它发生了。

回答by Ataginsky

A working exemple for WinCE

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 );
}

回答by prehistoricpenguin

Add an answer for libuv (though it's written in C), it has support for both Windows and Linux with system-specific APIs:

为 libuv 添加一个答案(尽管它是用 C 编写的),它支持 Windows 和 Linux,具有特定于系统的 API:

inotify on Linux, FSEvents on Darwin, kqueue on BSDs, ReadDirectoryChangesW on Windows, event ports on Solaris, unsupported on Cygwin

Linux 上的 inotify,Darwin 上的 FSEvents,BSD 上的 kqueue,Windows 上的 ReadDirectoryChangesW,Solaris 上的事件端口,在 Cygwin 上不受支持

You may check the document here, beware that the document says that the notification related APIs are not very consistent.

你可以查看这里的文档,注意文档说通知相关的API不是很一致。