简体   繁体   中英

Reading and writing objects into a binary file using C++?

I decided to read/write to a file using serialization; however, it only rights a few items. Our items are dynamically allocated through a test scripts then after they are all put into the vector they will then be put written into a script. The following is the code in our main function, the switch cases where we call the functions to read and write the objects, and lastly the functions where we attempt to write and read to the file. I do not know why it's only reading in a couple object, so any help would be great!

////////////////////////////////////////////////////////
// Main
int main(int argc, char *argv[]) {
    std::string optionInput;
    const char *const file_name = "data.dat";
    menuDisplay();

    while (loopBool) {
        std::cin.clear();
        if (selectedObject == SELECT_INIT) {
            std::cout << std::endl << "Menu (No Item): ";
        } else {
            std::cout << std::endl << "Item " << selectedObject << " Menu: ";
        }
        try {
            optionInput = menuInput();
        } catch (const Input_Error &) {
            std::cout << "Input error detected. Exiting.\n";
            break;
        }

        catch (...) {
            std::cout << "You should not be seeing this error message.\n";
            break;
        }
        std::cout << optionInput[0] << std::endl;
        optionSelect(optionInput[0]);
    }

    std::cout << "Exiting\n" << std::endl;
}

////////////////////////////////////////////////////////
// Case 'W'
case 'W': {
    // Writes authors to a file
    std::ofstream aSaveFile("authors.dat");
    boost::archive::text_oarchive aArchiveOut(aSaveFile);
    aArchiveOut << authorObject;

    // Writes mediaItem objects to a file
    std::ofstream mSaveFile("items.dat");
    boost::archive::text_oarchive mArchiveOut(mSaveFile);

    ioMediaInfo itemSender;
    for (int mediaWrite = 0; mediaWrite < mediaObject.size(); mediaWrite++) {
        itemSender.assignVariables(mediaObject[mediaWrite]);
        mArchiveOut << itemSender;
    }
    break;
}

////////////////////////////////////////////////////////
// Case 'Z'
case 'Z': {
    // Reads in authors to author array
    std::ifstream aReadFile("authors.dat");

    boost::archive::text_iarchive aArchiveIn(aReadFile);
    aArchiveIn >> authorObject;

    // Reads in mediaItems

    std::ifstream mReadFile("items.dat");

    boost::archive::text_iarchive mArchiveIn(mReadFile);

    std::string itemType;
    ioMediaInfo itemReciever;

    // for (int mediaRead = 0; mediaRead < 20; mediaRead++)
    // {

    mArchiveIn >> itemReciever;

    // Checks type of current object and creates a new mediaItem object in the vector to store it

    // TODO: Break case statement repetition into functions for greater code reuse

    itemType = itemReciever.getType();

    switch (itemType[0]) {
    case '*': {
        mediaObject.push_back(new mediaInfo());
        selectedObject++;
        mediaObject[selectedObject]->setName(itemReciever.getName());
        mediaObject[selectedObject]->setYear(itemReciever.getYear());
        mediaObject[selectedObject]->setEmpty(itemReciever.getEmpty());
        break;
    }
    case 'B': {
        mediaObject.push_back(new bookInfo());
        mediaObject[selectedObject]->setName(itemReciever.getName());
        mediaObject[selectedObject]->setEmpty(itemReciever.getEmpty());
        break;
    }
    case 'V': {
        mediaObject.push_back(new videoInfo());
        mediaObject[selectedObject]->setName(itemReciever.getName());
        mediaObject[selectedObject]->setEmpty(itemReciever.getEmpty());
        break;
    }
    case 'M': {
        mediaObject.push_back(new musicInfo());
        mediaObject[selectedObject]->setName(itemReciever.getName());
        mediaObject[selectedObject]->setEmpty(itemReciever.getEmpty());
        break;
    }
    default: { break; }
    }

    // }
    break;
}

////////////////////////////////////////////////////////
// assignVariable where we write to file
void ioMediaInfo::assignVariables(mediaInfo *originalMediaObject) {
    mediaItemName_ = originalMediaObject->getName();
    mediaItemYear_ = originalMediaObject->getYear();
    mediaItemPageNum_ = originalMediaObject->getPage();
    mediaItemPrint_ = originalMediaObject->getPrint();
    mediaItemValue_ = originalMediaObject->getValue();
    mediaItemType_ = originalMediaObject->getType();
    isEmpty_ = originalMediaObject->isEmpty();
    // mediaItemAuthor_ = originalMediaObject->getAuthor();
}

////////////////////////////////////////////////////////
// Where we read the file
void ioMediaInfo::printData() { std::cout << mediaItemName_ << std::endl; }

I think you're mixing paradigms. This looks very much like code taken from a bad C-style sample that used a fixed length array of manually allocated polymorphic ioMediaItem classes (that, to add insult to injury, contain and serialize a manual typeswitch mediaInfoType_ ).

Then you're driving a horrendously complicated loop to read items and maintain the collection invariants (presumably that type=='*' implies isEmpty() and that the vector of mediaInfoObjects contains no invalid objects etc).

Boost serialization was made so you do not have to worry about these things. Why use a complicated library if you're going to do all the clumsy managing and baby steps after all?

Just let go. Here's a taste of what it could be like:

Live On Coliru

#include <iostream>
#include <fstream> 
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/make_shared.hpp>

namespace Media {
    struct Author {
        std::string name;
        Author(std::string name = "") : name(std::move(name)) {}
    };

    using AuthorRef = boost::shared_ptr<Author>;

    struct CommonInfo {
        std::string name;
        int         year;
        AuthorRef   author;
    };

    struct BookInfo : CommonInfo {
        BookInfo() = default;

        int pageNum;
        int print;
        int value;

        BookInfo(CommonInfo ci, int pageNum, int print, int value) :
            CommonInfo(ci), pageNum(pageNum), print(print), value(value)
        { }
    };

    struct VideoInfo : CommonInfo {
        VideoInfo(CommonInfo ci = {}) : CommonInfo(ci) { }
    };

    struct MusicInfo : CommonInfo {
        MusicInfo(CommonInfo ci = {}) : CommonInfo(ci) { }
    };

    using Object  = boost::variant<BookInfo, MusicInfo, VideoInfo>;
    using Catalog = std::vector<Object>;

    ////// serialization methods
    static inline std::ostream& operator<<(std::ostream& os, CommonInfo const& ci) { return os << ci.name << " (" << ci.author->name << ")"; }

    // out-of-class serialization
    template <typename Ar> void serialize(Ar& ar, VideoInfo& o, unsigned) { ar & boost::serialization::base_object<CommonInfo>(o); }
    template <typename Ar> void serialize(Ar& ar, MusicInfo& o, unsigned) { ar & boost::serialization::base_object<CommonInfo>(o); }
    template <typename Ar> void serialize(Ar& ar, CommonInfo&o, unsigned) {
        ar & o.name & o.year & o.author;
    }
    template <typename Ar> void serialize(Ar& ar, Author& o,    unsigned) {
        ar & o.name;
    }
    template <typename Ar> void serialize(Ar& ar, BookInfo& o,  unsigned) {
        ar  & boost::serialization::base_object<CommonInfo>(o)
            & o.pageNum 
            & o.print
            & o.value
            ;
    }
}

struct Library {
    std::vector<Media::AuthorRef> authors; // to allow unreferenced authors
    Media::Catalog catalog;

    static Library makeSample();

    static Library load(std::string const& fname);
    void save(std::string const& fname) const;

    template <typename Ar> void serialize(Ar&ar,unsigned) {
        ar & authors & catalog;
    }
};

////////////////////////////////////////////////////////
// Main
int main() {
    Library::makeSample().save("authorsAndItems.dat");

    auto cloned = Library::load("authorsAndItems.dat");

    for (auto& obj : cloned.catalog)
        std::cout << obj << "\n";
}

using namespace Media;

Library Library::makeSample() {
    using boost::make_shared;
    // shared author
    auto multaScripserat = make_shared<Author>("Scripserat, Multa T.");

    return {
        {
            multaScripserat,
            boost::make_shared<Author>(Author{"Sufferer, A."}), // no books/music survived
        },
        {
            BookInfo { CommonInfo { "Title 1", 1999, multaScripserat }, 453, 7, 3 },
            BookInfo { CommonInfo { "Title 2", 2011, multaScripserat }, 200, 5, 1 },
            MusicInfo { { "Pop Album", 1972, make_shared<Author>("Beatles, The") } },
            MusicInfo { { "Title 2", 2011, multaScripserat } },
            VideoInfo { { "The Battleship Potemkin", 1925, make_shared<Author>("Eisenstein, Sergei") } },
        }
    };
}

void Library::save(std::string const& fname) const {
    std::ofstream ofs(fname, std::ios::binary);
    boost::archive::binary_oarchive oa(ofs);

    oa << *this;
}

Library Library::load(std::string const& fname) {
    std::ifstream ifs(fname, std::ios::binary);
    boost::archive::binary_iarchive ia(ifs);

    Library lib;
    ia >> lib;

    return lib;
}

Prints

Title 1 (Scripserat, Multa T.)
Title 2 (Scripserat, Multa T.)
Pop Album (Beatles, The)
Title 2 (Scripserat, Multa T.)
The Battleship Potemkin (Eisenstein, Sergei)

The hexdump of the authorsAndItems.dat file:

0000000: 1600 0000 0000 0000 7365 7269 616c 697a  ........serializ
0000010: 6174 696f 6e3a 3a61 7263 6869 7665 0b00  ation::archive..
0000020: 0408 0408 0100 0000 0000 0000 0000 0000  ................
0000030: 0000 0200 0000 0000 0000 0100 0000 0001  ................
0000040: 0000 0003 0001 0000 0000 0000 0000 1400  ................
0000050: 0000 0000 0000 5363 7269 7073 6572 6174  ......Scripserat
0000060: 2c20 4d75 6c74 6120 542e 0300 0100 0000  , Multa T.......
0000070: 0c00 0000 0000 0000 5375 6666 6572 6572  ........Sufferer
0000080: 2c20 412e 0000 0000 0005 0000 0000 0000  , A.............
0000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000a0: 0000 0000 0000 0000 0700 0000 0000 0000  ................
00000b0: 5469 746c 6520 31cf 0700 0003 0000 0000  Title 1.........
00000c0: 00c5 0100 0007 0000 0003 0000 0000 0000  ................
00000d0: 0007 0000 0000 0000 0054 6974 6c65 2032  .........Title 2
00000e0: db07 0000 0300 0000 0000 c800 0000 0500  ................
00000f0: 0000 0100 0000 0100 0000 0000 0000 0009  ................
0000100: 0000 0000 0000 0050 6f70 2041 6c62 756d  .......Pop Album
0000110: b407 0000 0300 0200 0000 0c00 0000 0000  ................
0000120: 0000 4265 6174 6c65 732c 2054 6865 0100  ..Beatles, The..
0000130: 0000 0700 0000 0000 0000 5469 746c 6520  ..........Title 
0000140: 32db 0700 0003 0000 0000 0002 0000 0000  2...............
0000150: 0000 0000 1700 0000 0000 0000 5468 6520  ............The 
0000160: 4261 7474 6c65 7368 6970 2050 6f74 656d  Battleship Potem
0000170: 6b69 6e85 0700 0003 0003 0000 0012 0000  kin.............
0000180: 0000 0000 0045 6973 656e 7374 6569 6e2c  .....Eisenstein,
0000190: 2053 6572 6765 69                         Sergei

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM