将二进制数据写入C中的文件很简单:使用fwrite,传递要写入的对象的地址和对象的大小。 Modern C ++是否有更“正确”的东西,还是应该坚持使用FILE *对象?据我所知,IOStream库用于编写格式化数据而不是二进制数据,而写入成员要求使用char *让我乱丢我的代码。
答案 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;
}
}
我希望你明白这一点。
可能你应该根据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
}