Reading and Writing std::vector<struct> to a file

I need to write a vector to a file, and then read it back into a vector.

The vector contains hundreds, possibly thousands, of structs which each contain 2 different structs.

I thought that the best way to do it would be to get the pointer with MyVector.data() and somehow write the data using that.

Just in case here’s a diagram of the vector:

MyVector
    - Struct 1
        - Struct A
            - float
            - float
            - bool
            ...
        - Struct B
            - float
            - float
            - bool
            ...
    - Struct 2
        - Struct A
            - float
            - float
            - bool
            ...
        - Struct B
            - float
            - float
            - bool
            ...

and so on.

I tried multiple methods, such as ofstream.write() and fwrite(), but none of them worked.

void PosBot::SaveMacro(std::string macroName) {
    int val = _mkdir("PosBot");

    std::string a = "PosBot/" + macroName + ".pbor";
    std::ofstream outfile(a.c_str(), std::ios_base::binary);
    std::copy(Frames.begin(), Frames.end(), std::ostreambuf_iterator<char>(outfile));
    outfile.close();
}

void PosBot::LoadMacro(std::string macroName) {
    Frames.clear();
    Checkpoints.clear();
    CheckpointFrames.clear();
    std::string a = "PosBot/" + macroName + ".pbor";
    std::ifstream infile(a.c_str(), std::ios_base::binary);
    std::istreambuf_iterator<char> iter(infile);
    std::copy(iter, std::istreambuf_iterator<char>(), std::back_inserter(Frames)); // this leaves newVector empty
    infile.close();
}

This gives me an error of:

binary ‘=’: no operator found which takes a right-hand operand of type ‘Frame’ (or there is no acceptable conversion)

>Solution :

std::ostreambuf_iterator writes character data to the output stream whenever it is assigned a single character via its operator=. Since you are specifying char as the CharT template parameter of std::ostreambuf_iterator, its operator= expects a char value to be assigned to it (ie, when used to write data from a std::vector<char>, std::string, etc), but you are trying to write Frame objects from a std::vector<Frame> instead. IOW, since you are trying to write Frame objects where char values are expected, that is why you are getting the conversion error on operator=.

You have a similar issue with reading in using std::istreambuf_iterator, too. It is meant for reading in character data (via its operator*), not structured data.

For what you are attempting to do, you need to use std::ostream_iterator (and std::istream_iterator) instead. You will simply have to define an overloaded operator<< (and operator>>) for Frame to write/read its member data to/from a std::ostream/std::istream as needed.

Try this:

std::ostream& operator<<(std::ostream& out, const Frame &frame) {
    // write Frame data to ostream as needed.  If Frame is a POD type,
    // you can write the whole thing in one go, eg...
    return out.write(reinterpret_cast<const char*>(&frame), sizeof(frame));

    // but, if Frame is not a POD type, you will have to write out
    // each data member individually instead...
}

std::istream& operator>>(std::istream& in, Frame &frame) {
    // read Frame data from istream as needed.  If Frame is a POD type,
    // you can read the whole thing in one go, eg...
    return in.read(reinterpret_cast<char*>(&frame), sizeof(frame));

    // but, if Frame is not a POD type, you will have to read in
    // each data member individually instead...
}

void PosBot::SaveMacro(std::string macroName) {
    int val = _mkdir("PosBot");

    std::string a = "PosBot/" + macroName + ".pbor";
    std::ofstream outfile(a.c_str(), std::ios_base::binary);
    std::copy(Frames.begin(), Frames.end(), std::ostream_iterator<Frame>(outfile));
    outfile.close();
}

void PosBot::LoadMacro(std::string macroName) {
    Frames.clear();
    Checkpoints.clear();
    CheckpointFrames.clear();
    std::string a = "PosBot/" + macroName + ".pbor";
    std::ifstream infile(a.c_str(), std::ios_base::binary);
    std::istream_iterator<Frame> iter(infile);
    std::copy(iter, std::istream_iterator<Frame>(), std::back_inserter(Frames));
    infile.close();
}

Leave a Reply