1

I've been trying to write the below object into a file and got lot of trouble since strings are dynamically allocated.

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

So I got to know that I can't just write into a file or read from a file an object with serialization. So I searched all over the internet about serialization with cpp and got to know about Boost library.But I wanted to do it my own (I know writing a library that already exist is not good, but I wanna see what's going on inside the code). So I got to know about overloading iostream << and >>. And I also know that serialize/deserialize into/from text.

But I want to serialize into a binary file. So I tried overloading ostream write and istream read. But then I got size issues(as write and read needs the sizeof the object it writes/reads).Then I also got to know about stringstream can help to serialize/deserialize objects into/from binary. But I don't how to do that?

So my real question is How to serialize and deserialize an object into/from binary files without third party libraries?

Ethan Rodrigo
  • 315
  • 1
  • 8
  • 1
    "*without third party libraries*" Then you're going to have to write all of the stuff those third party libraries have in them. That's why it's best to just use their code if you need it. – Nicol Bolas Oct 03 '21 at 15:12
  • Use `ios::binary` mode to open the file, and then use `ofstream::write` to write the size and content of the data structure into the file. – 康桓瑋 Oct 03 '21 at 15:15
  • 康桓瑋 As I have said since strings are dynamically allocated I can't just write the whole structure into a file. If I do so it will write the address of those objects into a file – Ethan Rodrigo Oct 04 '21 at 10:09
  • @EthanRodrigo and others can you please help me here https://stackoverflow.com/q/73953638/18230141 ? – James_sheford Oct 05 '22 at 10:39

1 Answers1

3

I have found a solution serialize and deserialize an object into/from a file. Here is an explaination

As I told you this is my class. And I have added two functions which overload the iostream's write and read.

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);
};

But I have also told you that I have tried this already. The problem I have was how to read without object member's size. So I made changes as below (Please read comments also).

// 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 '\0'
    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, '\0');  // delimiting character is '\0' 
    getline(in, obj.email, '\0');
    getline(in, obj.telephoneNo, '\0');
    in.read((char*)&obj.addmissionNo, sizeof(int));

    for (string& book: obj.issuedBooks){
        getline(in, book, '\0');
    }
            return in;
}

As you can see I have wrote length+1 for the terminating '\0'. It is usefull in read function as we have used getline instead of read. So getline reads until the '\0'. So no need of a size. And here I'm writing and reading into/from a file.

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');
}

That's how I solved my problem. If something wrong here please comment. Thank you!

Ethan Rodrigo
  • 315
  • 1
  • 8