如何在 ofstream 上进行 fsync?

发布于 2024-07-15 11:44:39 字数 344 浏览 7 评论 0原文

我想确保 ofstream 已写入磁盘设备。 执行此操作的可移植方式(在 POSIX 系统上可移植)是什么?

如果我在 read-only 附加模式下单独打开文件以获取文件描述符并使用它调用fsync,这是否可以解决问题? 像这样:

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

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

I want to make sure that an ofstream has been written to the disk device. What's the portable way (portable on POSIX systems) of doing this?

Does that solve the problem if I open the file separately in read-only append mode to get a file descriptor and call fsync with it? Like this:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

可爱咩 2024-07-22 11:44:39

如果您能够使用 Boost,请尝试基于 file_descriptor_sink 的流,例如:

#include <boost/filesystem.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <unistd.h>

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

If you're able to use Boost, try a file_descriptor_sink based stream, eg.:

#include <boost/filesystem.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <unistd.h>

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());
耳根太软 2024-07-22 11:44:39

不幸的是,纵观标准,basic_filebuf 或任何 basic_[io]?fstream 类模板都没有提供任何内容来允许您提取底层操作系统文件描述符(在就像 fileno() 对 C stdio I/O 所做的那样)。

也不存在将此类文件描述符作为参数的 open() 方法或构造函数(这将允许您使用不同的机制打开文件并记录文件句柄)。

basic_ostream::flush(),但是我怀疑这实际上并没有调用 fsync() ——我希望如此,就像 fflush()< /code> 在 stdio 中,它只确保用户空间运行时库缓冲区被刷新,这意味着操作系统仍然可以缓冲数据。

简而言之,似乎没有办法可移植地做到这一点。 :(

怎么办?我的建议是子类 basic_filebuf

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;

要使用它,您可以使用默认构造函数构造一个 ofstream,然后分配新的buffer with 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();

当然,您也可以从 basic_ostream 派生一个新类,以使打开文件和检索其文件描述符的过程更加方便。

Unfortunately, looking through the standard there is nothing provided by basic_filebuf or any of the basic_[io]?fstream class templates to allow you to extract the underlying OS file descriptor (in the way that fileno() does for C stdio I/O).

Nor is there an open() method or constructor that takes such a file descriptor as a parameter (which would allow you to open the file using a different mechanism and record the filehandle).

There is basic_ostream::flush(), however I suspect that this does not in fact call fsync() -- I expect that, like fflush() in stdio, it only makes sure that the user-space runtime library buffers are flushed, meaning that the OS could still be buffering the data.

So in short there appears to be no way to do this portably. :(

What to do? My suggestion is to subclass 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;

To use it, you can construct an ofstream using the default constructor, then assign the new buffer with 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();

Of course you could also derive a new class from basic_ostream to make the process of opening a file and retrieving its file descriptor more convenient.

多情癖 2024-07-22 11:44:39

std::filebuf 可能在其中的某个地方有一个文件描述符,但是获取它需要可怕的特定于实现的 hack。

这是 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()));
}

std::filebuf probably has a file descriptor somewhere inside it, but getting at it requires horrible implementation-specific hacks.

Here is one such horrible hack for 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()));
}
梦里南柯 2024-07-22 11:44:39

您根本无法在打开以供读取的文件描述符上进行 fsync() 操作。 在 Linux 中,fsync()记录为生成 EBADF如果描述符不处于写入模式。

You cannot portably do fsync() on a file descriptor open for reading, at all. In Linux, fsync() is documented as generating EBADF if the descriptor is not in write mode.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文