Vik*_*Vik 19 c++ fsync ofstream
我想确保已将一个ofstream写入磁盘设备.这样做的便携方式(可在POSIX系统上移植)是什么?
如果我open将文件分别以只读附加模式获取文件描述符并fsync用它调用,那么这是否解决了问题?像这样:
ofstream out(filename);
/* ...
write content into out
...
*/
out.close();
int fd = open(filename, O_APPEND);
fsync(fd);
close(fd);
Run Code Online (Sandbox Code Playgroud)
如果您能够使用Boost,请尝试基于file_descriptor_sink的流,例如:
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());
Run Code Online (Sandbox Code Playgroud)
不幸的是,通过标准查看,没有提供basic_filebuf任何basic_[io]?fstream类模板或任何类模板,以允许您提取底层OS文件描述符(与fileno()C stdio I/O的方式相同).
也没有一个open()方法或构造函数将这样的文件描述符作为参数(这将允许您使用不同的机制打开文件并记录文件句柄).
有basic_ostream::flush(),但是我怀疑,这实际上不呼fsync()-我想到的是,像fflush()在标准输入输出,它只可以确保用户空间运行时库缓冲区被刷新,这意味着操作系统仍然可以缓冲数据.
因此,简而言之,似乎没有办法可移植.:(
该怎么办?我的建议是子类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;
Run Code Online (Sandbox Code Playgroud)
要使用它,您可以ofstream使用默认构造函数构造一个,然后使用以下命令分配新缓冲区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();
Run Code Online (Sandbox Code Playgroud)
当然,您也可以从中派生一个新类,basic_ostream以便更方便地打开文件并检索其文件描述符.
std::filebuf里面可能有一个文件描述符,但是要获取它需要可怕的特定于实现的黑客。
这是 libstdc++ 的一个可怕的 hack。
#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()));
}
Run Code Online (Sandbox Code Playgroud)
您根本无法fsync()在打开以供读取的文件描述符上进行可移植的操作。在 Linux 中,如果描述符不处于写入模式,fsync()则记录为生成 EBADF。