C++ 在结构/类中读取/写入文件
我想将文件读入结构或类,但经过一番阅读,我发现这样做不是一个好主意:C++ 在结构/类中读取/写入文件,c++,class,struct,ifstream,ofstream,C++,Class,Struct,Ifstream,Ofstream,我想将文件读入结构或类,但经过一番阅读,我发现这样做不是一个好主意: int MyClass::loadFile( const char *filePath ) { ifstream file ( filePath, ios::in | ios::binary ); file.read ((char*)this, 18); file.close(); return 0; }
int MyClass::loadFile( const char *filePath ) {
ifstream file ( filePath, ios::in | ios::binary );
file.read ((char*)this, 18);
file.close();
return 0;
}
我猜如果我想从一个结构/类中编写一个文件,这也不是洁食:
void MyClass::writeFile( string fileName ) {
ofstream file( fileName, ofstream::binary );
file.write((char*)this, 18);
file.close();
}
听起来我不想这样做的原因是因为即使我的结构的数据成员加起来有18个字节,其中一些可能会在内存中被额外的字节填充。有没有一种更正确、更优雅的方法将文件放入这样的类/结构中?答案是:解决这个问题没有灵丹妙药 消除填充以确保类中的数据成员使用的一种方法是(在您正在使用的MSVC中) 这种方法的主要用途是如果您的类匹配预定义的格式,例如位图头。如果它是一个表示猫、狗的通用类,那么就不要使用这种方法。如果这样做是为了确保您知道编译器数据类型的字节长度,那么如果您的代码将是多平台的,那么您应该为成员使用显式大小,例如_int32等 如果这是一个常规类,那么在save成员中,每个值都应该显式写入。这样做的一个技巧是创建或从sourceforge或其他地方获取好的代码来帮助实现这一点。理想情况下,在一些允许命名成员的代码中,我使用类似于:
SET_WRITE_DOUBLE( L"NameOfThing", DoubleMemberOfClass );
SET_WRITE_INT( L"NameOfThing2", IntMemberOfClass );
// and so on...
我创建了这些宏背后的代码,我现在不分享这些代码,但是聪明的人可以创建自己的代码,以无序的方式保存命名为流的代码。我发现这是一种完美的方法,因为如果向类中添加或减去数据成员,则保存/加载不依赖于二进制表示形式和保存顺序,因为如果按顺序保存,类无疑会随着时间的推移而发展。这是您将要面临的问题
我希望这会有所帮助。首选的通用技术称为序列化 它没有二进制表示法那么脆弱。但它有需要解释的开销。标准类型可以很好地进行序列化,我们鼓励您将类序列化,以便可以轻松地序列化包含您的类的类
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;
}
class-MyClass{
int x;
浮动y;
双z;
friend std::ostream&operator(std::istream&s、MyClass&data);
};
std::ostream&运算符和输出数据.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.
}
intmain()
{
MyClass plop;
std::cout>plop;//从文件中读取。
std::矢量数据;
//将包含多个对象的文件读入向量。
std::ifstream loadFrom(“plop”);
std::copy(std::istream\u迭代器(loadFrom),std::istream\u迭代器(),
标准:背面插入器(数据)
);
//将对象向量写入文件。
std::ofstream saveTo(“Plip”);
std::copy(data.begin()、data.end()、std::ostream_迭代器(saveTo));
//注意:流迭代器(std::istream_迭代器)和(std::ostream_迭代器)
//在您的类型上模板化。它们使用流运算符(运算符>>)
//and(运算符)唯一真正的解决方案是逐个写入各个字段。Mind endianness,甚至更好,将每个字段转换为人类可读的表示形式(例如,数字42生成字符串“42”)在编写之前,这样您的文件就可以在标准文本编辑器中手动编辑。谢谢,我真的很感激。我在搜索中看到很多关于此的序列化弹出,但总是有人推荐boost库。我真的很讨厌不知道引擎盖下到底发生了什么,所以我一直避免使用其他库,直到我更理解C++。我想现在我将好好看看这个代码和一些序列化教程。再次感谢!我想我应该在我的帖子中提到这个,但是我正在使用位图和wave文件。这会改变你的答案还是序列化仍然是我们要走的路?@ RabyAlopopp:如果你有特定的文件格式,那么您需要遵循这些格式的规范。您不能假设编译器使用的内存布局与文件格式完全匹配。因此,您通常会专门编写每个元素,这通常意味着您必须编写特定的二进制大小(而不是sizeof(int))。您可能需要确保整数等内容符合网络字节顺序(请参阅规范以确保)请参阅和family。是的,我找到了这些文件的规范。我发布的代码是为了读取位图文件而编写的,根据规范,我可以使用前18个字节为任何位图提供相同的信息。读取每个元素似乎都很好,例如:[code]file.read((char*)&bmp\u id,2);file.read((char*)&bmp\u size,4);[/code],等等。序列化会比这更好吗?我一直觉得它太复杂了。在这种情况下,序列化不是你想要的技术。
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.
}