2009-03-24 10 views
14

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

¿Esto soluciona el problema si open el archivo por separado en modo de sólo lectura anexados para obtener un descriptor de archivo y llame fsync con ella? De esta manera:

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

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

Respuesta

3

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

+0

Ok, ¿qué ocurre si lo abro para anexarlo? – Vik

6

Desafortunadamente, mirando a través de la norma no hay nada proporcionada por basic_filebuf o cualquiera de las plantillas de clase basic_[io]?fstream para permitir que se extraiga el descriptor de archivo del sistema operativo subyacente (en la forma en que lo hace fileno() para C stdio E/S).

Ni hay un open() método o constructor que tome un descriptor de archivo como un parámetro (que le permita abrir el archivo usando un mecanismo diferente y grabar el identificador de archivo).

Hay basic_ostream::flush(), sin embargo sospecho que esto no es así, de hecho, llamada fsync() - espero que, como fflush() en stdio, sólo se asegura de que los amortiguadores de la biblioteca de espacio de usuario en tiempo de ejecución se vacían, lo que significa que el sistema operativo podría aún estar almacenando los datos.

En pocas palabras, parece que no hay forma de hacerlo de forma portátil. ? :(

Qué hacer Mi sugerencia es 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, se puede construir un ofstream utilizando el constructor por defecto, a continuación, asignar el nuevo buffer 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 puede obtener una nueva clase de basic_ostream para hacer más conveniente el proceso de abrir un archivo y recuperar su descriptor de archivo.

5

Si usted es capaz de usar Boost, tratar una corriente basada 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()); 
3

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

Aquí hay un truco tan 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())); 
} 
Cuestiones relacionadas