使用来自流的 boost binary_iarchive 序列化和反序列化
Posted
技术标签:
【中文标题】使用来自流的 boost binary_iarchive 序列化和反序列化【英文标题】:serialize and deserialise using boost binary_iarchive from sstream 【发布时间】:2017-03-28 20:42:35 【问题描述】:最后,经过一番努力,我找到了一种对std::map<int,map<int,structute values>
进行序列化和反序列化的方法,并且我能够打印这些值。
请您澄清一下我对以下代码的疑问
void serialize(archive & ar, const unsigned int version)
函数是否同时用于序列化和反序列化我们能否在每个类和结构中为序列化和反序列化设置单独的函数
同样的函数也可以用于创建 xml 吗,或者它是一种为 xml 提供单独的序列化和反序列化功能的好方法
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <map>
#include <boost/serialization/map.hpp>
struct values
std::string name;
std::string sex;
values():name("dummy"),sex("dummy") ;
template<class archive>
void serialize(archive & ar, const unsigned int version)
ar & name ;
ar & sex ;
;
class Myclass
public:
Myclass()
values val1;
e_group.insert( std::make_pair(1,val1) ) ;
e_group.insert( std::make_pair(2,val1) ) ;
p_group.insert( std::make_pair(1,e_group) ) ;
p_group.insert( std::make_pair(2,e_group) ) ;
template<class archive>
void serialize(archive & ar, const unsigned int version)
ar & e_group ;
ar & p_group;
typedef std::map<int,values> groups;
typedef std::map<int,groups> Pgroups;
groups e_group;
Pgroups p_group;
;
int main()
char buf[256];
Myclass obj;
std::stringstream os(std::ios_base::binary| std::ios_base::out| std::ios_base::in);
boost::archive::binary_oarchive oa(os, boost::archive::no_header);
oa << obj ;
// oa << make_binary_object(&e_group, sizeof(e_group));
//print binary data
std::string data = os.str();
for (uint8_t ch : data)
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(ch) << " ";
Myclass t2;
memcpy(buf, os.str().data(), os.str().length());
if(memcmp(buf, os.str().data(), os.str().length()) != 0)
printf("memcpy error\n");
std::stringstream is(std::string(buf, buf+os.str().length() ), std::ios_base::binary| std::ios_base::out| std::ios_base::in);
boost::archive::binary_iarchive ia(is, boost::archive::no_header);
ia >> t2;
for(auto &i:t2.p_group)
std::cout<<"\n"<<i.first<<"\n";
for(auto &j:i.second)
std::cout<<"\t"<<j.first<<"\t"<<j.second.name<<"\t"<<j.second.sex<<"\n";
return 0;
更新:我更新了 Richard 的代码并添加了一个函数来反序列化二进制文件
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <map>
#include <boost/serialization/map.hpp>
#include <boost/serialization/split_member.hpp>
struct values
std::string name;
std::string sex;
values():name("dummy"),sex("dummy") ;
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive>
void save(Archive & ar, const unsigned int version) const
// note, version is always the latest when saving
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(sex);
template<class Archive>
void load(Archive & ar, const unsigned int version)
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(sex);
;
class Myclass
public:
Myclass()
values val1;
e_group.insert( std::make_pair(1,val1) ) ;
e_group.insert( std::make_pair(2,val1) ) ;
p_group.insert( std::make_pair(1,e_group) ) ;
p_group.insert( std::make_pair(2,e_group) ) ;
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive>
void save(Archive & ar, const unsigned int version) const
// note, version is always the latest when saving
ar & BOOST_SERIALIZATION_NVP(e_group);
ar & BOOST_SERIALIZATION_NVP(p_group);
template<class Archive>
void load(Archive & ar, const unsigned int version)
ar & BOOST_SERIALIZATION_NVP(e_group);
ar & BOOST_SERIALIZATION_NVP(p_group);
typedef std::map<int,values> groups;
typedef std::map<int,groups> Pgroups;
groups e_group;
Pgroups p_group;
;
template<class Archive, class Object>
std::string serialise_to_string(Object const& assetlist)
auto os = std::ostringstream(std::ios::binary);
Archive arch os, boost::archive::no_header ;
arch << BOOST_SERIALIZATION_NVP(assetlist);
return os.str();
;
std::ostream& dump(std::ostream& os, std::string const& s)
const char *sep = "";
for (uint8_t ch : s)
std::cout << sep << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(ch);
sep = " ";
return os;
template<class Archive , class Object>
void deserialise_to_obj(std::string const &s1,Object &outObj)
std::stringstream is( s1, std::ios_base::binary| std::ios_base::out| std::ios_base::in);
Archive arch is, boost::archive::no_header ;
arch >> BOOST_SERIALIZATION_NVP(outObj);
;
int main()
Myclass obj ;
std::string s1 = serialise_to_string<boost::archive::binary_oarchive>(obj);
dump(std::cout, s1) << std::endl << std::endl;
auto s2 = serialise_to_string<boost::archive::xml_oarchive>(obj);
//Save xml to a file
std::ofstream ofs("output.xml");
ofs << s2 << std::endl << std::endl;
//Deserialize the binary data to object
Myclass outObj;
deserialise_to_obj<boost::archive::binary_iarchive>(s1,outObj);
//Print the object
for(auto &i:outObj.p_group)
std::cout<<"\n"<<i.first<<"\n";
for(auto &j:i.second)
std::cout<<"\t"<<j.first<<"\t"<<j.second.name<<"\t"<<j.second.sex<<"\n";
使用coliru编译的代码
请建议。如果我的方法是错误的,请告诉我
我要感谢 @sehe 和 @richard 帮助我提升。
谢谢 光辉
【问题讨论】:
【参考方案1】:首先,不要这样做:
memcpy(buf, os.str().data(), os.str().length());
if(memcmp(buf, os.str().data(), os.str().length()) != 0)
这只是创建了 4 个单独的字符串副本。
现在问题:
是 void serialize(archive & ar, const unsigned int version) 函数同时用于序列化和反序列化
是的
我们能否在每个类和结构中为序列化和反序列化设置单独的函数
是的
同样的函数也可以用于创建 xml 吗,或者它是一种为 xml 提供单独的序列化和反序列化功能的好方法
是的
您需要xml_oarchive
和宏BOOST_SERIALIZATION_SPLIT_MEMBER
和BOOST_SERIALIZATION_NVP
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/binary_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
#include <map>
#include <boost/serialization/map.hpp>
#include <boost/serialization/split_member.hpp>
struct values
std::string name;
std::string sex;
values():name("dummy"),sex("dummy") ;
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive>
void save(Archive & ar, const unsigned int version) const
// note, version is always the latest when saving
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(sex);
template<class Archive>
void load(Archive & ar, const unsigned int version)
ar & BOOST_SERIALIZATION_NVP(name);
ar & BOOST_SERIALIZATION_NVP(sex);
;
class Myclass
public:
Myclass()
values val1;
e_group.insert( std::make_pair(1,val1) ) ;
e_group.insert( std::make_pair(2,val1) ) ;
p_group.insert( std::make_pair(1,e_group) ) ;
p_group.insert( std::make_pair(2,e_group) ) ;
BOOST_SERIALIZATION_SPLIT_MEMBER();
template<class Archive>
void save(Archive & ar, const unsigned int version) const
// note, version is always the latest when saving
ar & BOOST_SERIALIZATION_NVP(e_group);
ar & BOOST_SERIALIZATION_NVP(p_group);
template<class Archive>
void load(Archive & ar, const unsigned int version)
ar & BOOST_SERIALIZATION_NVP(e_group);
ar & BOOST_SERIALIZATION_NVP(p_group);
typedef std::map<int,values> groups;
typedef std::map<int,groups> Pgroups;
groups e_group;
Pgroups p_group;
;
template<class Archive, class Object>
std::string serialise_to_string(Object const& o)
auto os = std::ostringstream(std::ios::binary);
Archive arch os, boost::archive::no_header ;
arch << BOOST_SERIALIZATION_NVP(o);
return os.str();
;
std::ostream& dump(std::ostream& os, std::string const& s)
const char *sep = "";
for (uint8_t ch : s)
std::cout << sep << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(ch);
sep = " ";
return os;
int main()
char buf[256];
Myclass obj;
auto s1 = serialise_to_string<boost::archive::binary_oarchive>(obj);
dump(std::cout, s1) << std::endl << std::endl;
auto s2 = serialise_to_string<boost::archive::xml_oarchive>(obj);
std::cout<< s2 << std::endl << std::endl;
return 0;
示例输出:
00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79 02 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79 00 00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79 02 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79 02 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79 02 00 00 00 05 00 00 00 00 00 00 00 64 75 6d 6d 79 05 00 00 00 00 00 00 00 64 75 6d 6d 79
<o class_id="0" tracking_level="0" version="0">
<e_group class_id="1" tracking_level="0" version="0">
<count>2</count>
<item_version>0</item_version>
<item class_id="2" tracking_level="0" version="0">
<first>1</first>
<second class_id="3" tracking_level="0" version="0">
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
<item>
<first>2</first>
<second>
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
</e_group>
<p_group class_id="4" tracking_level="0" version="0">
<count>2</count>
<item_version>0</item_version>
<item class_id="5" tracking_level="0" version="0">
<first>1</first>
<second>
<count>2</count>
<item_version>0</item_version>
<item>
<first>1</first>
<second>
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
<item>
<first>2</first>
<second>
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
</second>
</item>
<item>
<first>2</first>
<second>
<count>2</count>
<item_version>0</item_version>
<item>
<first>1</first>
<second>
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
<item>
<first>2</first>
<second>
<name>dummy</name>
<sex>dummy</sex>
</second>
</item>
</second>
</item>
</p_group>
</o>
【讨论】:
为什么要拆分加载/保存?实现是相同的,这使得它不必要的开销 @sehe 我认为这就是他要求的 - 是的,问题 2。 他问“是否用于序列化和反序列化的 void serialize(archive & ar, const unsigned int version) 函数” - 答案是“是” 我也真的困惑你从哪里得到他“想要”xml档案的想法。 (我碰巧从其他问题中知道他也想要这个,但这不是问题所在?) @sehe 那是 q1,我没有回答。以上是关于使用来自流的 boost binary_iarchive 序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章
在 boost::archive::binary_iarchive 上的 std::bad_alloc
有啥方法可以包装 boost“tee”流的构造以进行自动类型推断?