2016-07-27 13 views
2

Nehmen wir an, ich den folgenden Code haben:Wie zu zwingen Datei Spülung

#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)); 
    } 
} 

(beachten Sie, dass ich einen flush Anruf nach jedem Schreibvorgang haben)

Ich habe bemerkt, dass diese Anwendung nicht aktualisiert " zuletzt geänderte Zeit "und" Größe "Attribute der" test.log "-Datei, es sei denn, ich mache einen Rechtsklick auf diese Datei oder öffne sie.

Ich vermute, dass dies auf eine interne Pufferung zurückzuführen ist (das System möchte nicht so zeitaufwendige Operationen wie eine tatsächliche I/O auf die Festplatte machen, es sei denn, dazu gezwungen). Habe ich recht?

Ich muss eine Anwendung schreiben, die auf Änderungen in Protokolldateien achten soll, die von anderen Anwendungen erstellt wurden (ich kann sie nicht ändern). Zuerst dachte ich an FileSystemWatcher Klasse in C#, aber ich habe festgestellt, dass es das gleiche Verhalten (es wird kein entsprechendes Ereignis ausgelöst, wenn Datei in einer Quellanwendung geschlossen wurde oder wurde durch Rechtsklick auf diese Datei in Windows Explorer zu aktualisieren)). Was kann ich dann tun? Rufen Sie WinAPI-Funktionen wie GetFileAttributes für jede Datei auf, nach der ich so oft wie möglich suchen möchte?

+0

Ich denke, Sie leiden unter Standard-Windows-Pufferung, besonders häufig auf Netzlaufwerken. Da es nicht sofort bemerkt, sind Sie halb dazu verdammt, zu warten, bis Windows das Schreiben auf Platte bestätigt - dies kann auch durch Plattenpufferung verursacht werden, obwohl dies nicht sehr sinnvoll ist, da Windows den Schreibvorgang bei Windows puffert hat es tatsächlich noch nicht begangen, andere Teile sehen es nicht – BugFinder

+0

@Jovasa Nun, Total Commander hat genau das gleiche Verhalten – FrozenHeart

+0

@BugFinder ich sehe. Aber ich habe sowieso ein Problem zu lösen.Ich muss einen korrekten Weg finden, um diese 'Flush's zu erzwingen, die von anderen Anwendungen gemacht wurden. – FrozenHeart

Antwort

2

Es gibt zwei verschiedene Dinge hier. Zuerst wird die letzte modifizierte Zeit in der Datei MFT record (inode equivalent) jedes Mal aktualisiert, wenn Sie darauf schreiben.

Die von FindFirstFile und Freunde zurückgegebenen Informationen stammen jedoch nicht aus der Datei, sondern aus Informationen, die im Verzeichniseintrag zwischengespeichert wurden. Dieser Cache wird immer dann aktualisiert, wenn eine Datei geschlossen wird, die über diesen Verzeichniseintrag geöffnet wurde. Dies sind die Informationen, die von den meisten Anwendungen wie Windows Explorer und dem Befehl DIR angezeigt werden.

Wenn Sie wissen möchten, wann eine Datei aktualisiert wurde, müssen Sie das Äquivalent einer Unix stat Operation ausführen, die den MFT-Datensatz (Inode) liest. Dazu müssen Sie einen Handle für die Datei öffnen, GetFileInformationByHandle aufrufen und den Handle erneut schließen.

Die zweite Sache ist, dass es einen guten Grund gibt, dies nicht zu tun. Wenn ein Programm in eine Datei schreibt, kann es einen Teil des Schreibprozesses durchlaufen. Daher befindet sich die Datei möglicherweise in einem ungültigen (beschädigten) Status. Um sicherzustellen, dass die Datei in einem gültigen Zustand ist, sollten Sie warten, bis die Datei geschlossen wurde. Auf diese Weise wissen Sie, dass die Datei nun bereit ist, sich anzusehen.

Sobald das Schreibprogramm das Schreiben in die Datei beendet hat, wird der Verzeichniseintrag aktualisiert und FileSystemWatcher zeigt die Datei an.

Wenn Sie absolut sicher sind, dass Sie Benachrichtigungen zu Dateien sehen möchten, die noch geschrieben werden, können Sie das USN Change Journal als Option ansehen. Ich weiß nicht, ob dies aktueller ist als die Verzeichniseinträge, das müssen Sie untersuchen.

+0

Ich muss nach Dateiänderungen im Verzeichnis suchen. In diesem Moment kann ich mich nicht auf die 'FileSystemWatcher' Klasse aus C# verlassen. Was kann ich dann tun? Manuell über alle Dateien im Verzeichnis iterieren, öffnen und auf Änderungen warten? – FrozenHeart

+0

Also, 'flush'ing eine Datei ** tut ** tatsächlich gepufferten Inhalt auf der Festplatte, habe ich recht? Weil ich nicht sicher bin, ob Windows Explorer/Total Commander nur die zwischengespeicherten Dateiinformationen anzeigt (z. B. Zeitpunkt und Größe der letzten Änderung) oder das System tatsächlich nur einen internen Puffer löscht **, wenn ich mit der rechten Maustaste auf diese Datei klicke/diese öffne/Schließen Sie es in der Anwendung – FrozenHeart

+1

Spülen einer Datei schreibt den Inhalt auf die Festplatte. Es aktualisiert den Verzeichniseintrag einfach nicht. –