我目前正在实施ping / pong缓冲方案,以便安全地将文件写入磁盘。我在Linux / CentOS机器上使用C ++ / Boost。现在我面临的问题是强制将文件实际写入磁盘。无论文件系统的所有缓存策略(ext3 / ext4)/ SO自定义规则/ RAID控制器/硬盘控制器是否都可以这样做?
最好使用普通的fread()/ fwrite(),c ++ ostream还是boost文件系统?
我听说只是刷新文件(fflush())并不保证实际写入
答案 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));
答案 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 );
}
(这只是经过表面测试,但基本的想法就在那里。)