2009-03-24 14 views
14

Ich möchte sicherstellen, dass ein Ofstream auf das Laufwerk Gerät geschrieben wurde. Was ist der portable Weg (tragbar auf POSIX-Systemen), dies zu tun?Wie fsync auf einem ofstream zu tun?

Heißt das, das Problem zu lösen, wenn ich die Datei separat in read-only Anfügemodus open einen Dateideskriptor zu erhalten und fsync mit ihm nennen? Wie folgt aus:

ofstream out(filename); 
/* ... 
    write content into out 
    ... 
*/ 
out.close(); 

int fd = open(filename, O_APPEND); 
fsync(fd); 
close(fd); 

Antwort

3

Sie können nicht portabel machen fsync() auf einem Dateideskriptor zum Lesen geöffnet, die alle auf. In Linux ist fsync()documented als EBADF generieren, wenn der Deskriptor nicht im Schreibmodus ist.

+0

Ok, was ist, wenn ich es zum Anhängen öffne? – Vik

6

Leider Blick durch den Standard nichts von basic_filebuf oder einen des basic_[io]?fstream Klassen-Templates zur Verfügung gestellt ist, damit Sie das zugrunde liegende Betriebssystem Dateideskriptor (in der Weise, dass fileno() tut für C stdio I/O) zu extrahieren.

Es gibt auch keine open() Methode oder Konstruktor, der einen solchen Dateideskriptor als Parameter verwendet (wodurch Sie die Datei mit einem anderen Mechanismus öffnen und das Dateihandle aufzeichnen könnten).

Es gibt basic_ostream::flush(), aber ich vermute, dass dies in der Tat nicht Anruf fsync() - Ich erwarte, dass, wie fflush() in stdio, es nur dafür sorgt, dass die User-Space-Laufzeitbibliothek Puffer gespült werden, was bedeutet, dass das Betriebssystem konnte Puffer weiterhin die Daten.

Kurz gesagt scheint es keine Möglichkeit zu geben, dies portabel zu machen. ? :(

Was zu tun ist, Mein Vorschlag basic_filebuf<C, T> Unterklasse:

template <typename charT, typename traits = std::char_traits<charT> > 
class my_basic_filebuf : public basic_filebuf<charT, traits> { 
    .... 

public: 
    int fileno() { ... } 
    .... 
}; 

typedef my_basic_filebuf<char> my_filebuf; 

, es zu benutzen, können Sie ein ofstream mit dem Standard-Konstruktor konstruieren, weist dann die neuen Puffer mit rdbuf():

my_filebuf buf; 
buf.open("somefile.txt"); 

ofstream ofs; 
ofs.rdbuf(&buf); 

ofs << "Writing to somefile.txt..." << endl; 
int fd = static_cast<my_filebuf*>(ofs.rdbuf())->fileno(); 

Natürlich könnten Sie auch eine neue Klasse von basic_ostream ableiten, um den Prozess des Öffnens einer Datei und das Abrufen des Dateideskriptors bequemer zu machen.

5

Wenn Sie in der Lage sind Boost zu verwenden, versuchen Sie einen file_descriptor_sink basierten Strom, zB .:

boost::filesystem::path filePath("some-file"); 
boost::iostreams::stream<boost::iostreams::file_descriptor_sink> file(filePath); 

// Write some stuff to file. 

// Ensure the buffer's written to the OS ... 
file.flush(); 

// Tell the OS to sync it with the real device. 
// 
::fdatasync(file->handle()); 
3

std::filebuf wahrscheinlich einen Dateideskriptor irgendwo im Inneren, aber es immer erfordert schreckliche Umsetzung spezifischen Hacks.

Hier ist eine solche schreckliche Hack für libstdC++.

#include <fstream> 
#include <unistd.h> 

int GetFileDescriptor(std::filebuf& filebuf) 
{ 
    class my_filebuf : public std::filebuf 
    { 
    public: 
    int handle() { return _M_file.fd(); } 
    }; 

    return static_cast<my_filebuf&>(filebuf).handle(); 
} 

int main() 
{ 
    std::ofstream out("test"); 

    out << "Hello, world!"; 
    out.flush(); 

    fsync(GetFileDescriptor(*out.rdbuf())); 
}