2012-02-14 7 views
2

Windows 7用のVisual Studio 2008 C++アプリケーションを使用して、ファイルを変更したいと思っています。Windows 7の変更点を調べるファイル

ファイルは次のように変更することがあります。

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


更新 は、私は、ジャーナル機能を使用しようとしています。しかし、私はカップルの問題を抱えています。

  1. FSCTL_READ_USN_JOURNALは即座に戻ります。ブロックされません。 (しかし、これは問題2に関連しているかもしれません)
  2. 私のハンドルがどこに指しているかにかかわらず(私はディレクトリ "C:\ Foo \ Bar"と "C:\ Foo \ Bar" \ MyFile.txt ")私はC:ボリュームに何らかの変更を加えたようです。 FSCTL_READ_USN_JOURNALが私に与えるものを制限する方法はありますか?

簡潔にするため、エラーチェックは省略されています。

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の\バーのディレクトリ):

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 
+0

よろしくお願いします。しかし、もう少し作業が必要です!私はあなたのためにいくつかの情報についてネットを検索しています。数分で戻ってください! –

+1

は私が学んだことを発見しました:http://www.microsoft.com/msj/0999/journal/journal.aspxおよびhttp://www.microsoft.com/msj/1099/journal2/journal2.aspx –

+0

ボリューム全体ではなく特定のファイルを監視するためのコード例と、指定されたシステムファイルだけでなく、すべてのシステムファイルを監視するようにも見えます。ただし、close()だけでなくflush()の後でもファイルの変更を検出できることに注意してください。だから、間違いなく他の方法よりも効果的です。 – PaulH

答えて

2

あなたは、ファイルシステムの変更を検出する唯一の100%garanteedの道をだ

(MSDNのドキュメントを参照してください)

変更ジャーナルオペレーション

を使用することができます。 しかしそれはかなり複雑です。

+0

私が理解しているように、それはどのような変更が加えられたのかを教えてくれますが、変更が加えられたときに警告を受ける仕組みはありません。 – PaulH

+0

私はこれを確信していますが、正しく使用されたときに、ReasonMaskフィルタで指定されたファイル(\ READ_USN_JOURNAL_DATA)にファイル交換が行われたときに返されるブロック操作(DeviceIoControlを通して)があることを覚えているようです。 –

+0

私はかなり複雑だと言ったように。ドキュメントを慎重に学習する必要があります。インターネット上のいくつかの例がありますが、私はそれらを覚えていません(私の他のマシンでは今はアクセスできません)。 –

0

いいえ、あなたはファイルハンドルを閉じるまで、単一のバイトがこれまでに取得する保証はありませんので、 OSによって書かれたものです。

ファイルハンドルにflushを呼び出してから、Windows API関数FlushFileBuffersを呼び出すことによって例外が発生する可能性がありますが、プログラムがファイルに書き込みを行っていない限り、バイトが書き込まれない可能性があります。

+1

'std :: endl'はフラッシュを行います。 27.6.2.7メモ帳でファイルを開くと(ハンドルが閉じられる前に)、データが書き込まれたことがわかります。 – PaulH

0

これは、FASTIO_WRITE操作とIRP_MJ_WRITE操作を監視するフィルター・ドライバーを使用して行うことができます。 Hereはかなり良いハウツー記事です。

+0

)唯一の方法ではありません。 b)他の(以前の)フィルタドライバの(良好な)動作に依存します。 C)変更ジャーナルのみANY変更の100%検出を保証します。 –

+0

私は、他の動作不良のフィルタドライバは実用的な問題ではないと思いますが、私の答えを編集して "唯一の方法"という言葉を削除しました。また、DeviceIoControlで行うこともできますが、リアルタイムでは実行できません。これは、OPが望んでいるようです。 DeviceIoControlを使用するにはポーリングが必要です。非常にゆっくりとペースで行うことができない限り、これは本当に醜い解決策です。 –

+0

ポーリングを必要とせず、タイムアウトが経過した場合、または要求された変更が発生した場合にのみ返される、正しく設定されたデータ構造を持つDeviceIoControl関数が使用されています。 –

1

特定のファイルまたはディレクトリのデータを読み取るには、FSCTL_READ_USN_JOURNALの代わりにFSCTL_READ_FILE_USN_DATAを使用すると思います。私は後者が常にボリューム全体のデータを取得すると信じています。しかし、取得したUSNレコードのTimeStamp,Reason、またはSourceInfoフィールドには記入されません。あなたがそれらを必要とするならば、私はあなたが読むことを望む正確なUSNを指定して、FSCTL_READ_USN_JOURNALでそれらを読むことができると信じています。

+0

良い点、私は、それらのFSCTLコードの1つ(またはそれ以上)がタイムスタンプと理由情報を提供しないことを忘れていました。それはとても複雑です! –

関連する問題