2016-07-27 52 views
2

假設我有以下代碼:如何強制文件刷新

#include <chrono> 
#include <fstream> 
#include <thread> 

int main() 
{ 
    std::ofstream f("test.log"); 

    int i = 0; 
    while (true) 
    { 
    f << i++; 
    f.flush(); 

    std::this_thread::sleep_for(std::chrono::milliseconds(100)); 
    } 
} 

(請注意,我每次寫操作後flush調用)

我注意到,這個應用程序不更新「 「test.log」文件的「最後修改時間」和「大小」屬性,除非我右鍵單擊該文件或打開它。

我想這是由於內部緩衝(系統不希望將這種耗時的操作作爲磁盤的實際I/O,除非被迫這樣做)。我對嗎?

我需要編寫一個應用程序,該應用程序應該監視由其他應用程序創建的日誌文件中的更改(我無法更改它們)。起初,我想到了C#中的FileSystemWatcher類,但我注意到它具有相同的行爲(它不會觸發相應的事件,除非在源應用程序中關閉了文件,或者通過在Windows資源管理器中右鍵單擊該文件來強制更新)。那我該怎麼辦?爲我想要經常查找的每個文件調用WinAPI函數,如GetFileAttributes

+0

我認爲你正在遭受標準窗口緩衝,尤其是在網絡驅動器上常見的問題。在那個它沒有立即注意到,你註定要等到Windows確認寫入磁盤 - 這也可能是由磁盤緩衝引起的,因爲儘管它沒有多大意義,因爲Windows緩衝了寫入,如果窗口還沒有實際承諾,其他部分沒有看到它 – BugFinder

+0

@Jovasa那麼,Total Commander具有完全相同的行爲 – FrozenHeart

+0

@BugFinder我看到了。但我有一個問題要解決。我需要找到一種正確的方法來強制這些由其他應用程序創建的「flush」 – FrozenHeart

回答

2

這裏有兩件獨立的事情。首先,文件MFT記錄(inode相當於)上的最後一次修改時間爲,每次您向其寫入時都會更新。

FindFirstFile和朋友返回的信息不是來自文件,而是來自緩存在目錄條目中的信息。只要關閉文件即可通過該目錄條目打開該緩存。這是大多數應用程序(如Windows資源管理器)和命令提示符DIR命令顯示的信息。

如果您想知道文件何時更新,您需要執行相當於讀取MFT記錄(inode)的Unix操作stat。這需要打開文件的句柄,調用GetFileInformationByHandle並再次關閉句柄。

第二件事是有一個很好的理由不這樣做。如果一個程序正在寫入一個文件,那麼它可能是寫作過程中的一部分。因此該文件可能處於無效(損壞)狀態。爲確保文件處於有效狀態,您應該等到文件關閉。這就是你如何知道該文件現在已準備好查看。

寫入程序寫入文件後,目錄條目將被更新,FileSystemWatcher將顯示該文件。

如果您確定要查看仍處於編寫過程中的文件的通知,則可以查看USN更改日誌作爲選項。我不知道這是否保持比目錄條目更新,你將不得不調查。

+0

我需要查看特定目錄中的文件更改。此時,我不能依賴C#中的'FileSystemWatcher'類。那我該怎麼辦?手動迭代目錄中的所有文件,打開它並觀察更改? – FrozenHeart

+0

所以,flush一個文件**確實會將任何緩衝的內容寫入磁盤,對吧?因爲我不確定Windows資源管理器/ Total Commander是否僅顯示緩存的文件信息(例如上次修改時間和大小),或者系統實際僅刷新內部緩衝區** **當我右鍵單擊/打開該文件/在應用程序中關閉它 – FrozenHeart

+1

刷新文件將內容寫入磁盤。它只是不更新​​目錄條目。 –