如何在Modern C ++中将二进制数据写入文件?

时间:2015-02-26 14:45:54

标签: c++11

将二进制数据写入C中的文件很简单:使用fwrite,传递要写入的对象的地址和对象的大小。 Modern C ++是否有更“正确”的东西,还是应该坚持使用FILE *对象?据我所知,IOStream库用于编写格式化数据而不是二进制数据,而写入成员要求使用char *让我乱丢我的代码。

2 个答案:

答案 0 :(得分:4)

因此,这里的游戏是在阅读和写作上启用参数依赖查找,并确保您不会尝试读取/写入非平面数据的内容。

它无法捕获包含指针的数据,这也不应该以这种方式读/写,但它总比没有好

namespace serialize {
  namespace details {
    template<class T>
    bool write( std::streambuf& buf, const T& val ) {
      static_assert( std::is_standard_layout<T>{}, "data is not standard layout" );
      auto bytes = sizeof(T);
      return buf.sputn(reinterpret_cast<const char*>(&val), bytes) == bytes;
    }
    template<class T>
    bool read( std::streambuf& buf, T& val ) {
      static_assert( std::is_standard_layout<T>{}, "data is not standard layout" );
      auto bytes = sizeof(T);
      return buf.sgetn(reinterpret_cast<char*>(&val), bytes) == bytes;
    }
  }
  template<class T>
  bool read( std::streambuf& buf, T& val ) {
    using details::read; // enable ADL
    return read(buf, val);
  }
  template<class T>
  bool write( std::streambuf& buf, T const& val ) {
    using details::write; // enable ADL
    return write(buf, val);
  }
}

namespace baz {
    // plain old data:
    struct foo {int x;};
    // not standard layout:
    struct bar {
      bar():x(3) {}
      operator int()const{return x;}
      void setx(int s){x=s;}
      int y = 1;
    private:
      int x;
    };
    // adl based read/write overloads:
    bool write( std::streambuf& buf, bar const& b ) {
        bool worked = serialize::write( buf, (int)b );
        worked = serialize::write( buf, b.y ) && worked;
        return worked;
    }
    bool read( std::streambuf& buf, bar& b ) {
        int x;
        bool worked = serialize::read( buf, x );
        if (worked) b.setx(x);
        worked = serialize::read( buf, b.y ) && worked;
        return worked;
    }
}

我希望你明白这一点。

live example

可能你应该根据is_pod而不是标准布局限制所说的写作,并认为如果在构造/破坏上发生特殊情况,也许你不应该是二进制blitting类型。

答案 1 :(得分:2)

由于您已经绕过所有格式化,我建议您直接使用std::filebuf类来避免std::fstream可能带来的开销;由于RAII,它肯定比FILE*好。

遗憾的是,你无法以这种方式摆脱演员阵容。但是包装起来并不难,比如:

template<class T>
void write(std::streambuf& buf, const T& val)
{
    std::size_t to_write = sizeof val;
    if (buf.sputn(reinterpret_cast<const char*>(&val), to_write) != to_write)
        // do some error handling here
}