如何序列化和反序列化对象到/从二进制文件手动?



我一直在尝试将下面的对象写入文件中,由于字符串是动态分配的,因此遇到了很多麻烦。

class Student{
string name, email, telephoneNo;
int addmissionNo;
vector<string> issued_books;
public:
// There are some methods to initialize name, email, etc...
};

所以我知道我不能直接用serialization向文件中写入或从文件中读取对象。所以我在网上搜索了关于cpp序列化的所有信息,并了解了Boost库。但我想自己做(我知道编写一个已经存在的库并不好,但我想看看代码内部发生了什么)。所以我了解了重载流<<>>。我还知道序列化/反序列化到/从文本

但是我想序列化成二进制文件。所以我尝试重载ostreamwrite和istreamread。但是后来我遇到了大小问题(因为写和读需要它写/读的对象的大小)。然后我也知道了stringstream可以帮助将对象序列化/反序列化成二进制文件。但我不知道该怎么做?

所以我真正的问题是如何序列化和反序列化一个对象到/从二进制文件没有第三方库?

我找到了一个解决方案,将对象序列化和反序列化到/从文件中。以下是解释

我告诉过你这是我的课。我还添加了两个函数来重载iostream的写和读操作。

class Student{
string name, email, telephoneNo;
int addmissionNo;
vector<string> issuedBooks;
public:
void create();  // initialize the private members
void show();  // showing details
// and some other functions as well...

// here I'm overloading the iostream's write and read
friend ostream& write(ostream& out, Student& obj);
friend istream& read(istream& in, Student& obj);
};

但我也告诉过你,我已经试过了。我的问题是如何读取没有对象成员的大小。所以我做了如下修改(也请阅读评论)。

// write: overload the standard library write function and return an ostream
// @param out: an ostream
// @param obj: a Student object
ostream& write(ostream& out, Student& obj){
// writing the objet's members one by one.
out.write(obj.name.c_str(), obj.name.length() + 1); // +1 for the terminating ''
out.write(obj.email.c_str(), obj.email.length() + 1);
out.write(obj.telephoneNo.c_str(), obj.telephoneNo.length() + 1);
out.write((char*)&obj.addmissionNo, sizeof(obj.addmissionNo)); // int are just cast into     a char* and write into the object's member

// writing the vector of issued books   
for (string& book: obj.issuedBooks){
out.write(book.c_str(), book.length() + 1);
}
return out;
}

// read: overload the standard library read function and return an istream
// @param in: an istream
// @param obj: a Student object
istream& read(istream& in, Student& obj){
// getline is used rather than read
// since getline reads a whole line and can be give a delim character
getline(in, obj.name, '');  // delimiting character is '' 
getline(in, obj.email, '');
getline(in, obj.telephoneNo, '');
in.read((char*)&obj.addmissionNo, sizeof(int));
for (string& book: obj.issuedBooks){
getline(in, book, '');
}
return in;
}

您可以看到,我为终止的''写了length+1。它在read函数中很有用,因为我们使用了getline而不是read。所以getline读取到''。所以不需要尺寸。这里我正在写入和读取一个文件

void writeStudent(Student s, ofstream& f){
char ch; // flag for the loop
do{
s.create(); // making a student        
f.open("students", ios::app | ios::binary); // the file to be written
write(f, s); // the overloaded function
f.close();
cout << "Do you want to add another record? (y/n): ";
cin >> ch;
cin.ignore();
} while(toupper(ch) == 'Y'); // loop until user stop adding records. 
}
void readStudent(Student s, ifstream& f){
char ch; // flag for the loop
do{
f.open("students", ios::in | ios::binary);

cout << "Enter the account no of the student: ";
int no;
cin >> no;
int found = 0;
while (read(f, s)){
if (s.retAddmissionNo() == no){
found = 1;
s.show();
}
}
if (!found)
cout << "Account Not found!n";

f.close();
cout << "Do you want another record? (y/n): ";
cin >> ch;
} while(toupper(ch) == 'Y');
}

我就是这样解决我的问题的。如果这里有什么问题,请评论。谢谢你!