c++c++11

Saving Class Object to Binary File


I am looking for an easy way to save and load this C++ object to and from a binary file.

#include <iostream>
#include <vector>

class User
{
private:
    std::string _name;
    int _age;
    std::vector<std::string> _hobbies;
public:
    std::string Name() { return _name; }
    int Age() { return _age; }

    std::vector<std::string> Hobbies() { return _hobbies; }
    void Hobbies(std::string hobbieName)
    {
        _hobbies.push_back(hobbieName);
    }

    User(std::string name, int age)
    {
        _name = name;
        _age = age;
    }
};

int main()
{
    User u1 = User("John", 48);
    u1.Hobbies("Art");
    u1.Hobbies("Lego");
    u1.Hobbies("Blogging");

    User u2 = User("Jane", 37);
    u2.Hobbies("Walking");
    u2.Hobbies("Chess");
    u2.Hobbies("Card Games");

    std::cout << u1.Name() << "'s Hobbies:\n";
    for (std::string hobbie : u1.Hobbies())
    {
        std::cout << hobbie << "\n";
    }

    std::cout << u2.Name() << "'s Hobbies:\n";
    for (std::string hobbie : u2.Hobbies())
    {
        std::cout << hobbie << "\n";
    }

    //Save 'u1' to file.

    //Load 'u1' from file into a new 'User' object
}

I have looked at a number of StackOverflow answers for similar questions, but I am struggling to find a solution specifically regarding using the vector in my class. I would appreciate any suggestions that you might have.


Solution

  • Here is a very abstract idea of what you want, Write string size that helps to read string back for name, write age, again wite hobbies size that helps to read it again and finally write each string with it size. To read reverse the process,

    #include <iostream>
    #include <fstream>
    #include <vector>
    
    class User
    {
    private:
        std::string _name;
        int _age;
        std::vector<std::string> _hobbies;
    
    public:
        std::string Name()
        { 
          return _name;
        }
    
        int Age()
        { 
          return _age;
        }
    
        std::vector<std::string> Hobbies()
        { 
          return _hobbies;
        }
    
        void Hobbies(std::string hobbieName)
        {
            _hobbies.push_back(hobbieName);
        }
    
        User(std::string name, int age)
        {
            _name = name;
            _age = age;
        }
    
        /**
         * @brief saves to user binary file
         * 
         * @param fout 
         */
        void save(std::ofstream &fout)
        {
            // write name
            size_t nsiz = this->_name.size();
            // write string size to read
            fout.write((const char *)(&nsiz), sizeof(nsiz));
            fout.write(&_name[0], nsiz);
    
            // write age
            fout.write((const char *)&_age, sizeof(int));
    
            // write hobbies size
            size_t hsiz = _hobbies.size();
            fout.write((const char *)&hsiz, sizeof(size_t));
    
            // write hobbies
            for (auto &str : _hobbies)
            {
                size_t ssiz = str.size();
                fout.write((const char *)(&ssiz), sizeof(ssiz));
                fout.write(&str[0], str.size());
            }
        }
    
        /**
         * @brief loads from binary file
         * 
         * @param fin 
         */
        void load(std::ifstream &fin)
        {
            // read name
            size_t nsiz = 0;
            fin.read((char*)&nsiz, sizeof(size_t));
            this->_name.resize(nsiz);
            fin.read(&_name[0], nsiz);
    
            // read age
            fin.read((char*)&_age, sizeof(int));
    
            // read hobbies size
            size_t hsiz = 0;
            fin.read((char*)(&hsiz), sizeof(hsiz));
            _hobbies.resize(hsiz);
    
            for(size_t i = 0; i < hsiz; ++i)
            {
                size_t ssiz = 0;
                fin.read((char*)&ssiz, sizeof(size_t));
                _hobbies[i].resize(ssiz);
                fin.read(&_hobbies[i][0], ssiz);
            }
        }
    };
    
    int main()
    {
        User u1 = User("John", 48);
    
        u1.Hobbies("Art");
        u1.Hobbies("Lego");
        u1.Hobbies("Blogging");
    
        std::ofstream fout("data.bin", std::ofstream::binary);
        u1.save(fout);
        fout.close();
    
        User u2("", 0);
    
        std::ifstream fin("data.bin", std::ifstream::binary);
        u2.load(fin);
        fin.close();
    
        std::cout << u2.Name() << " with age " << u2.Age() << "'s Hobbies:\n";
    
        for (std::string hobbie : u2.Hobbies())
        {
            std::cout << hobbie << "\n";
        }
    }
    
    

    I hope that it helps, and make sure to do things what if string size is zero :)