我想将一个文件读入一个结构或类,但经过一些阅读后,我已经收集到这样做的好主意:
int MyClass::loadFile( const char *filePath ) {
ifstream file ( filePath, ios::in | ios::binary );
file.read ((char*)this, 18);
file.close();
return 0;
}
我猜我是否想要从struct / class写一个文件,这不是犹太人:
void MyClass::writeFile( string fileName ) {
ofstream file( fileName, ofstream::binary );
file.write((char*)this, 18);
file.close();
}
这听起来像是我不想这样做的原因是因为即使我的struct的数据成员加起来为18个字节,其中一些可能会在内存中填充额外的字节。是否有更正确/更优雅的方式将文件放入类/结构中?
答案 0 :(得分:2)
首选的通用技术称为序列化。
它比二进制表示更脆弱。但它需要解释的开销。标准类型适用于序列化,我们鼓励您对类进行序列化,以便可以轻松地序列化包含类的类。
class MyClass {
int x;
float y;
double z;
friend std::ostream& operator<<(std::ostream& s, MyClass const& data);
friend std::istream& operator>>(std::istream& s, MyClass& data);
};
std::ostream& operator<<(std::ostream& s, MyClass const& data)
{
// Something like this
// Be careful with strings (the input>> and output << are not symmetric unlike other types)
return str << data.x << " " << data.y << " " << data.z << " ";
}
// The read should be able to read the version printed using <<
std::istream& operator>>(std::istream& s, MyClass& data)
{
// Something like this
// Be careful with strings.
return str >> data.x >> data.y >> data.z;
}
用法:
int main()
{
MyClass plop;
std::cout << plop; // write to a file
std::cin >> plop; // read from a file.
std::vector<MyClass> data;
// Read a file with multiple objects into a vector.
std::ifstream loadFrom("plop");
std::copy(std::istream_iterator<MyClass>(loadFrom), std::istream_iterator<MyClass>(),
std::back_inserter(data)
);
// Write a vector of objects to a file.
std::ofstream saveTo("Plip");
std::copy(data.begin(), data.end(), std::ostream_iterator<MyClass>(saveTo));
// Note: The stream iterators (std::istream_iterator) and (std::ostream_iterator)
// are templatized on your type. They use the stream operators (operator>>)
// and (operator<<) to read from the stream.
}
答案 1 :(得分:0)
答案是:这个问题没有灵丹妙药。
一种可以消除填充的方法,以确保您的类中的数据成员使用(在您正在使用的MSVC中)
#pragma pack( push, 1 )
class YourClass {
// your data members here
int Data1;
char Data2;
// etc...
};
#pragma pack( pop )
此方法的主要用途是,如果您的类匹配预定义的格式,例如位图标头。如果它是代表猫,狗的通用类,那么不管怎么说都不要使用这种方法。如果这样做的另一件事是确保你知道编译器的数据类型的字节长度,如果你的代码永远是多平台,那么你应该为成员使用显式大小,如__int32等。
如果这是一般类,那么在保存成员中,应该显式写入每个值。这样做的一个提示是创建或从sourceforge或某个好的代码获取,以帮助做到这一点。理想情况下,一些允许成员命名的代码,我使用类似的东西:
SET_WRITE_DOUBLE( L"NameOfThing", DoubleMemberOfClass );
SET_WRITE_INT( L"NameOfThing2", IntMemberOfClass );
// and so on...
我创建了这些宏背后的代码,我现在不分享,但是聪明的人可以创建自己的代码来保存命名为无序集中的流。我发现这是一个完美的方法,因为如果你向类中添加或减去数据成员,保存/加载不依赖于二进制表示和保存的顺序,因为如果你按顺序保存,你的类无疑会随着时间的推移而发展是你将面临的一个问题。
我希望这会有所帮助。