如何在C++中使用boost庫序列化自定義class ?| serialize and deserialize a class in cpp with boost

本文首發於我的博客kezunlin.me/post/6887a6…,歡迎閱讀!ios

serialize and deserialize a class in cppapp

Guide

how to serialize string

size + dataless

The easiest serialization method for strings or other blobs with variable size is to serialize first the size as you serialize integers, then just copy the content to the output stream.socket

When reading you first read the size, then allocate the string and then fill it by reading the correct number of bytes from the stream.ide

with ostream/istream

native way with ostream/istream for example class MyClass with height,width,name fields.post

class MyClass {
public:
    int height;
   int width;
   std::string name;
}

std::ostream& MyClass::serialize(std::ostream &out) const {
    out << height;
    out << ',' //number seperator
    out << width;
    out << ',' //number seperator
    out << name.size(); //serialize size of string
    out << ',' //number seperator
    out << name; //serialize characters of string
    return out;
}
std::istream& MyClass::deserialize(std::istream &in) {
    if (in) {
        int len=0;
        char comma;
        in >> height;
        in >> comma; //read in the seperator
        in >> width;
        in >> comma; //read in the seperator
        in >> len;  //deserialize size of string
        in >> comma; //read in the seperator
        if (in && len) {
            std::vector<char> tmp(len);
            in.read(tmp.data() , len); //deserialize characters of string
            name.assign(tmp.data(), len);
        }
    }
    return in;
}複製代碼

overload for operator<< and operator>>ui

std::ostream& operator<<(std::ostream& out, const MyClass &obj)
{
    obj.serialize(out); 
    return out;
}

std::istream& operator>>(std::istream& in, MyClass &obj)
{
    obj.deserialize(in); 
    return in;
}複製代碼

with boost serialization

archive file formatthis

  • text: textiarchive,textoarchive field
  • xml: xmliarchive,xmloarchive, with BOOST_SERIALIZATION_NVP(field)
  • binary: binaryiarchive,binaryoarchive with stringstream or fstream.

text archive

change BOOST_SERIALIZATION_NVP(field) to fieldspa

xml archive

#include <boost/archive/text_iarchive.hpp> 
#include <boost/archive/text_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 
#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/binary_iarchive.hpp> 
#include <boost/archive/binary_oarchive.hpp> 
#include <iostream> 
#include <fstream> 
#include <sstream>

class Camera {

public:
    int id;
    std::string name;
    double pos;
};

namespace boost {
    namespace serialization {

        template<class Archive>
        void serialize(Archive& archive, Camera& cam, const unsigned int version)
        {
            archive & BOOST_SERIALIZATION_NVP(cam.id);
            archive & BOOST_SERIALIZATION_NVP(cam.name);
            archive & BOOST_SERIALIZATION_NVP(cam.pos);
        }

    } // namespace serialization
} // namespace boost

std::ostream& operator<<(std::ostream& cout, const Camera& cam)
{
    cout << cam.id << std::endl
        << cam.name << std::endl
        << cam.pos << std::endl;
    return cout;
}

void save()
{
    std::ofstream file("archive.xml");
    boost::archive::xml_oarchive oa(file);
    
    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & BOOST_SERIALIZATION_NVP(cam);
}

void load()
{
    std::ifstream file("archive.xml");
    boost::archive::xml_iarchive ia(file);
    Camera cam;
    ia & BOOST_SERIALIZATION_NVP(cam);
    std::cout << cam << std::endl;
}

void test_camera()
{
    save();
    load();
}

int main(int argc, char** argv)
{
    test_camera();
}
複製代碼

binary archive

void save_load_with_binary_archive()
{
    // binary archive with stringstream
    std::ostringstream oss;
    boost::archive::binary_oarchive oa(oss);

    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & (cam);

   # get binary content
    std::string str_data = oss.str();
    std::cout << str_data << std::endl;

    std::istringstream iss(str_data);
    boost::archive::binary_iarchive ia(iss);
    Camera new_cam;
    ia & (new_cam);
    std::cout << new_cam << std::endl;
}複製代碼

binary archive with poco SocketStream

client.cppcode

void test_client()
{
    SocketAddress address("127.0.0.1", 9911);
    StreamSocket socket(address);
    SocketStream stream(socket);
    //Poco::StreamCopier::copyStream(stream, std::cout);

    boost::archive::binary_oarchive oa(stream);
    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & (cam);
}複製代碼

server.cpp

void run()
    {
        Application& app = Application::instance();
        app.logger().information("Request from " + this->socket().peerAddress().toString());
        try
        {
            SocketStream stream(this->socket());
            //Poco::StreamCopier::copyStream(stream, std::cout);

            boost::archive::binary_iarchive ia(stream);
            Camera new_cam;
            ia & (new_cam);
            std::cout << new_cam << std::endl;
        }
        catch (Poco::Exception& exc)
        {
            app.logger().log(exc);
        }
    }複製代碼

notes on std::string

Even know you have seen that they do the same, or that .data() calls .c_str(), it is not correct to assume that this will be the case for other compilers. It is also possible that your compiler will change with a future release.

2 reasons to use std::string:

std::string can be used for both text and arbitrary binary data.

//Example 1
//Plain text:
std::string s1;
s1 = "abc";
s1.c_str();

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);
s2.data();複製代碼

boost archive style

intrusive

  • `private template
    void serialize(Archive& archive, const unsigned int version)`
  • friend class boost::serialization::access;
class Camera {

public:
    int id;
    std::string name;
    double pos;

private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& archive, const unsigned int version)
    {
        archive & BOOST_SERIALIZATION_NVP(id);
        archive & BOOST_SERIALIZATION_NVP(name);
        archive & BOOST_SERIALIZATION_NVP(pos);
    }
};複製代碼

non-intrusive

class Camera {

public:
    int id;
    std::string name;
    double pos;
};


namespace boost {
    namespace serialization {

        template<class Archive>
        void serialize(Archive& archive, Camera& cam, const unsigned int version)
        {
            archive & BOOST_SERIALIZATION_NVP(cam.id);
            archive & BOOST_SERIALIZATION_NVP(cam.name);
            archive & BOOST_SERIALIZATION_NVP(cam.pos);
        }

    } // namespace serialization
} // namespace boost複製代碼

boost archive type

shared_ptr

boost::shared_ptr instead of std::shared_prt and

#include <boost/serialization/shared_ptr.hpp>
複製代碼

Reference

History

  • 20180128: created.
  • 20180129: add intrusive,non-intrusive part.

Copyright

相關文章
相關標籤/搜索