强制将文件写入磁盘

时间:2012-11-13 09:42:00

标签: c++ linux unix disk fflush

我目前正在实施ping / pong缓冲方案,以便安全地将文件写入磁盘。我在Linux / CentOS机器上使用C ++ / Boost。现在我面临的问题是强制将文件实际写入磁盘。无论文件系统的所有缓存策略(ext3 / ext4)/ SO自定义规则/ RAID控制器/硬盘控制器是否都可以这样做?

最好使用普通的fread()/ fwrite(),c ++ ostream还是boost文件系统?

我听说只是刷新文件(fflush())并不保证实际写入

3 个答案:

答案 0 :(得分:5)

fflush(对于FILE *),std :: flush(对于IOStream)强制程序发送到操作系统。

POSIX

  • sync(2)要求安排写入缓冲区,但可以在写入完成之前返回(Linux正在等待数据在返回之前发送到硬件)。

  • fsync(2)保证等待数据发送到硬件,但需要一个文件描述符(你可以从文件中获取一个文件*(3),我知道没有标准从IOStream中获取一个的方法。

  • O_SYNC作为打开(2)的标志。

在所有情况下,硬件可能都有自己的缓冲区(但是如果它有控制权,那么一个好的实现也会尝试冲洗它们,并且ISTR认为某些磁盘正在使用电容器,这样它们就能够冲洗发生的任何事情。电源)和网络文件系统都有自己的警告。

答案 1 :(得分:2)

您可以使用fsync()/ fdatasync()强制(注释1)数据到存储上。 那些需要文件描述符,如例如打开()。 linux manpage有更多的linux特定信息,特别是fsync和fdatasync的区别。

如果不直接使用文件解析器,许多抽象将包含驻留在您的进程中的内部缓冲区。

e.g。如果您使用FILE *,则首先必须从应用程序中清除数据。

//... open and write data to a FILE *myfile
fflush(myfile);
fsync(fileno(myfile));
  • 注1:这些调用强制操作系统确保将任何OS缓存中的任何数据写入驱动器,并且驱动器会确认该事实。许多硬盘驱动器都会向操作系统提出此问题,并可能将数据填入驱动器的高速缓存内存中。

答案 2 :(得分:0)

不在标准C ++中。你必须使用某种特定于系统的 IO,类似于open,在Unix下具有O_SYNC标志,然后是write

请注意,ostream(和... C,FILE*)被缓冲。如果你不确切知道什么时候是什么 写入磁盘,然后坚持这个没有多大意义 写入的事务完整性。 (这不会太难 设计一个streambuf,当您进行显式刷新时,写入, 但是。)

编辑:

举个简单的例子:

class SynchronizedStreambuf : public std::streambuf
{
    int myFd;
    std::vector<char> myBuffer;

protected:
    virtual int overflow( int ch );
    virtual int sync();

public:
    SynchronizedStreambuf( std::string const& filename );
    ~SynchronizedStreambuf();
};

int SynchronizedStreambuf::overflow( int ch )
{
    if ( myFd == -1 ) {
        return traits_type::eof();
    } else if ( ch == traits_type::eof() ) {
        return sync() == -1 ? traits_type::eof() : 0;
    } else {
        myBuffer.push_back( ch );
        size_t nextPos = myBuffer.size();
        myBuffer.resize( 1000 );
        setp( &myBuffer[0] + nextPos, &myBuffer[0] + myBuffer.size() );
        return ch;
    }
}

int SynchronizedStreambuf::sync()
{
    size_t toWrite = pptr() - &myBuffer[0];
    int result = (toWrite == 0 || write( myFd, &myBuffer[0], toWrite ) == toWrite ? 0 : -1);
    if ( result == -1 ) {
        close( myFd );
        setp( NULL, NULL );
        myFd = -1;
    } else {
        setp( &myBuffer[0], &myBuffer[0] + myBuffer.size() );
    }
    return result;
}

SynchronizedStreambuf::SynchronizedStreambuf( std::string const& filename )
    : myFd( open( filename.c_str(), O_WRONLY | O_CREAT | O_SYNC, 0664 ) )
{
}

SynchronizedStreambuf::~SynchronizedStreambuf()
{
    sync();
    close( myFd );
}

(这只是经过表面测试,但基本的想法就在那里。)