c++ ofstream fsync

c++ - ¿Cómo hacer fsync en un ofstream?



(4)

Quiero asegurarme de que se haya escrito un ofstream en el dispositivo de disco. ¿Cuál es la forma portátil (portátil en sistemas POSIX) de hacer esto?

¿Resuelve el problema si open el archivo por separado en modo de solo lectura para obtener un descriptor de archivo y llamar a fsync con él? Me gusta esto:

ofstream out(filename); /* ... write content into out ... */ out.close(); int fd = open(filename, O_APPEND); fsync(fd); close(fd);


Desafortunadamente, mirando a través del estándar no hay nada provisto por basic_filebuf o ninguna de las plantillas de clase basic_[io]?fstream para permitirle extraer el descriptor de archivo del SO subyacente (de la manera en que fileno() hace para C stdio I / O) .

Tampoco existe un método o constructor open() que tome dicho descriptor de archivo como un parámetro (lo que le permitiría abrir el archivo utilizando un mecanismo diferente y registrar el identificador de archivo).

Existe basic_ostream::flush() , sin embargo, sospecho que en realidad no llama a fsync() . Supongo que, como fflush() en stdio, solo se asegura de que los búferes de la biblioteca en tiempo de ejecución del espacio de usuario estén vaciados, lo que significa que el sistema operativo todavía podría estar almacenando los datos.

Entonces, en resumen, no parece haber manera de hacerlo de manera portátil. :(

¿Qué hacer? Mi sugerencia es la subclase basic_filebuf<C, T> :

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;

Para usarlo, puedes construir un ofstream utilizando el constructor predeterminado, luego asignar el nuevo búfer con 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();

Por supuesto, también podría derivar una nueva clase de basic_ostream para hacer que el proceso de abrir un archivo y recuperar su descriptor de archivo sea más conveniente.


No puede hacer fsync() de forma portátil en un descriptor de archivo abierto para leer, en absoluto. En Linux, se documented que fsync() genera EBADF si el descriptor no está en modo de escritura.


Si puede usar Boost, pruebe una secuencia basada en file_descriptor_sink, por ejemplo:

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());


std::filebuf probablemente tiene un descriptor de archivo en algún lugar dentro de él, pero llegar a él requiere horribles hacks específicos de implementación.

Aquí hay un hack horrible para 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())); }