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

时间:2022-02-16 07:07:28

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++中,是否有一种相对简单的方法来实现这种功能(不一定要独立于平台)?

5 个解决方案

#1


78  

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 QFileSystemWatcher which 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)

There is a Win32 api called FindFirstChangeNotification which 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 directory which will get you started.

有一个名为FindFirstChangeNotification的Win32 api,它可以完成这项工作。有一篇很好的文章,它是api的一个小包装类,它调用了如何在指定的目录中发生更改,从而获得通知。

Windows (.NET Framework)

Yes some people do use C++/CLI with the .NET Framework. System.IO.FileSystemWatcher is your class of choice. Microsoft has a nice article on how to monitor file system changes using this class.

是的,有些人确实在。net框架中使用c++ /CLI。先。文件系统监视程序是您选择的类。Microsoft有一篇关于如何使用这个类监视文件系统更改的漂亮文章。

OS X

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

FSEvents API是OS X 10.5的新版本,功能非常全面。

Linux

Use inotify as Alex mentioned in his answer.

使用inotify,正如Alex在他的回答中提到的。

#2


17  

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/Inotify and the many links from it for example. For Windows, see http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx .

如果您不需要独立于平台,那么在Linux上的方法可能比“轮询”(定期检查)更少,请参见http://en.wikipedia.org/wiki/Inotify和它的许多链接。有关Windows,请参见http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx。

#3


4  

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发生。

#4


3  

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

SimpleFileWatcher可能是您正在寻找的。当然,这是一种外部依赖——也许你没有选择。

#5


2  

A working exemple for 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 );
}

#1


78  

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 QFileSystemWatcher which 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)

There is a Win32 api called FindFirstChangeNotification which 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 directory which will get you started.

有一个名为FindFirstChangeNotification的Win32 api,它可以完成这项工作。有一篇很好的文章,它是api的一个小包装类,它调用了如何在指定的目录中发生更改,从而获得通知。

Windows (.NET Framework)

Yes some people do use C++/CLI with the .NET Framework. System.IO.FileSystemWatcher is your class of choice. Microsoft has a nice article on how to monitor file system changes using this class.

是的,有些人确实在。net框架中使用c++ /CLI。先。文件系统监视程序是您选择的类。Microsoft有一篇关于如何使用这个类监视文件系统更改的漂亮文章。

OS X

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

FSEvents API是OS X 10.5的新版本,功能非常全面。

Linux

Use inotify as Alex mentioned in his answer.

使用inotify,正如Alex在他的回答中提到的。

#2


17  

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/Inotify and the many links from it for example. For Windows, see http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx .

如果您不需要独立于平台,那么在Linux上的方法可能比“轮询”(定期检查)更少,请参见http://en.wikipedia.org/wiki/Inotify和它的许多链接。有关Windows,请参见http://msdn.microsoft.com/en-us/library/aa365261(VS.85).aspx。

#3


4  

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发生。

#4


3  

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

SimpleFileWatcher可能是您正在寻找的。当然,这是一种外部依赖——也许你没有选择。

#5


2  

A working exemple for 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 );
}