在Windows 7中查看文件以进行更改

时间:2012-02-14 15:22:27

标签: c++ windows file-io

我有一个适用于Windows 7的Visual Studio 2008 C ++应用程序,我想在其中查看文件以进行更改。

文件可能会改变如下:

std::ofstream myfile_;

void LogData( const char* data )
{
    myfile_ << data << std::endl;
    // note that the file output buffer is flushed by std::endl, but the file is not closed.
}

我尝试使用带有FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_SECURITY | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME标志的ReadDirectoryChangesW和FindFirstChangeNotification来查看文件的目录。但是,在文件句柄实际关闭之前,这些API都不会检测文件更改。

有没有办法在实际写入文件时检测到更改,但是在文件句柄关闭之前?

谢谢, PaulH


更新 在@ Edwin的建议下,我正在尝试使用Journal功能。但是,我有几个问题。

  1. FSCTL_READ_USN_JOURNAL立即返回。它不会阻止。 (但是,这可能与问题2有关)
  2. 无论我的句柄指向哪里(我尝试打开目录“C:\ Foo \ Bar”的句柄和文件“C:\ Foo \ Bar \ MyFile.txt”)我似乎得到任何对C:卷的更改。有没有办法限制FSCTL_READ_USN_JOURNAL给我的东西?
  3. 为简洁起见,省略了错误检查。

    boost::shared_ptr< void > directory( 
        ::CreateFileW( L"C:\\Foo\\Bar\\Myfile.txt", 
                       GENERIC_READ, 
                       FILE_SHARE_READ, 
                       NULL, 
                       OPEN_EXISTING, 
                       FILE_ATTRIBUTE_NORMAL, 
                       NULL ), 
        ::CloseHandle );
    
    USN_JOURNAL_DATA journal = { 0 };
    DWORD returned = 0;
    ::DeviceIoControl( directory.get(), FSCTL_QUERY_USN_JOURNAL, NULL, 0, &journal, sizeof( journal ), &returned, NULL );
    
    BYTE buffer[ 4096 ] = { 0 };
    READ_USN_JOURNAL_DATA read = { 0, USN_REASON_DATA_EXTEND | USN_REASON_DATA_TRUNCATION, FALSE, 0, 0, journal.UsnJournalID };
    ::DeviceIoControl( directory.get(), FSCTL_READ_USN_JOURNAL, &read, sizeof( read ), &buffer, sizeof( buffer ), &returned, NULL );
    
    for( USN_RECORD* record = ( USN_RECORD* )( buffer + sizeof( USN ) );
         ( ( BYTE* )record - buffer ) < returned;
         record = ( USN_RECORD* )( ( BYTE* )record + record->RecordLength ) )
    {
        ATLTRACE( L"%s\r\n", record->FileName );
    }
    

    示例输出(这些都不在C:\ Foo \ Bar目录中):

    AeXProcessList.txt`
    AeXProcessList.txt`
    AeXAMInventory.txt`
    AeXAMInventory.txt`
    AeXProcessList.txt`
    AeXProcessList.txtP
    access.log`
    mysqlgeneral.log
    E804.tmp
    apache_error.log
    E804.tmp
    CHROME.EXE-5FE9909D.pfh
    CHROME.EXE-5FE9909D.pfp
    SyncData.sqlite3-journal
    CHROME.EXE-5FE9909D.pfh
    CHROME.EXE-5FE9909D.pfP
    1211.tmp
    SyncData.sqlite3-journal
    AeXAMInventory.txt
    

4 个答案:

答案 0 :(得分:2)

您可以使用

  

更改日记帐操作

(参见MSDN文档)

这是检测文件系统中任何变化的唯一100%保证方式。 但这很复杂。

答案 1 :(得分:1)

要读取特定文件或目录的数据,我相信您要使用FSCTL_READ_FILE_USN_DATA而不是FSCTL_READ_USN_JOURNAL。我相信后者总是检索整个卷的数据。但是,这不会填写您获得的USN记录的TimeStampReasonSourceInfo字段。如果您需要这些,我相信您可以使用FSCTL_READ_USN_JOURNAL阅读它们,并指定您想要阅读的确切USN。

答案 2 :(得分:0)

不,因为在关闭文件句柄之前,无法保证操作系统只能写入一个字节。

异常可能是通过调用文件句柄上的flush然后调用Windows API函数FlushFileBuffers,但除非写入文件的程序执行此操作,否则不会写入任何字节。

答案 3 :(得分:0)

这可以通过监视FASTIO_WRITE和IRP_MJ_WRITE操作的过滤器驱动程序来完成。 Here是一篇非常好的指导文章。