Reputation: 7853
I have a Visual Studio 2008 C++ application for Windows 7 where I would like to watch a file for changes.
The file may be changed like this:
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.
}
I have tried watching the file's directory using both ReadDirectoryChangesW and FindFirstChangeNotification with 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
flags. But, neither of those APIs will detect file changes until the file handle is actually closed.
Is there any way to detect a change when the file is actually written, but before the file handle is closed?
Thanks, PaulH
Update On @Edwin's suggestion, I'm attempting to use the Journal feature. But, I'm having a couple issues.
FSCTL_READ_USN_JOURNAL
gives me?Error checking omitted for brevity.
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 );
}
Example output (none of these are in the C:\Foo\Bar directory):
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
Upvotes: 2
Views: 2962
Reputation: 490108
To read data for a specific file or directory, I believe you want to use FSCTL_READ_FILE_USN_DATA
instead of FSCTL_READ_USN_JOURNAL
. I believe the latter always retrieves data for an entire volume. That does not, however, fill in the TimeStamp
, Reason
, or SourceInfo
fields of the USN record you get. If you need those, I believe you can read them with FSCTL_READ_USN_JOURNAL
, specifying the exact USN you want to read.
Upvotes: 1
Reputation: 6846
This can be done with a filter driver that monitors the FASTIO_WRITE and IRP_MJ_WRITE operations. Here is a pretty good how-to article.
Upvotes: 0
Reputation: 3929
You can use
Change Journal Operations
(see MSDN docs)
That's the only 100% garanteed way to detect any change in the filesystem. But it's pretty complicated.
Upvotes: 2
Reputation: 117681
No, because until you close the file handle there is no guarantee a single byte ever gets written by the OS.
The exception would probably be by calling flush
on your file handle and then call the Windows API function FlushFileBuffers
, but unless the program writing into the file does this no bytes probably get written.
Upvotes: 0