C ++:将对象写入和读取到二进制文件中

时间:2015-04-25 01:08:22

标签: c++ serialization boost vector io

我决定使用序列化来读/写文件;但是,它只限制了几件物品。我们的项目是通过测试脚本动态分配的,然后在它们全部放入向量后,它们将被写入脚本。以下是我们的main函数中的代码,我们调用函数来读取和写入对象的开关情况,最后是我们尝试写入和读取文件的函数。我不知道为什么它只能阅读几个对象,所以任何帮助都会很棒!

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

1 个答案:

答案 0 :(得分:0)

我认为你们正在混合范式。这看起来非常类似于使用固定长度数组的手动分配的多态ioMediaItem类的错误C样式示例(为了增加损伤,包含并序列化手动类型切换mediaInfoType_)。

然后你正在驱动一个非常复杂的循环来读取项目并维护集合不变量(可能是type=='*'暗示isEmpty()并且mediaInfoObjects的向量不包含无效对象等) 。

进行了Boost序列化,因此必须担心这些事情。如果你打算做所有笨拙的管理和婴儿步骤,为什么要使用复杂的图书馆呢?

放手吧。这里有一种可能的样子:

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

打印

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

authorsAndItems.dat文件的hexdump:

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