C++中将对象进行序列化的经常使用方法有三种:protobuf、 Boost.Serializatio、MFC Serialization。编程
根据使用场景,各有优点网络
- protobuf :须要单独定义格式,通常用于网络通讯,用于数据包的传输。
- Boost.Serializatio : 可以建立或重建程序中的等效结构,并保存为二进制数据、文本数据、XML或者实用户本身定义的其它文件
- MFC Serialization: MFC 对 CObject 类中的序列化提供内置支持
对于如下小型项目,若是须要保持程序中的等效结构,但又不想引入boost库的话,其实也能够自行实现,基于二进制的序列化与反序列化并不难,下面将详细介绍实现过程,支持C++基础类类型及stl容器类型。测试
测试效果:spa
void print(const std::string& msg) { //反序列化 std::istringstream iss(msg); std::vector<std::string> d; Deserialize(iss, d); for(auto item : d) { std::cout << item << std::endl; } int val; Deserialize(iss, val); std::cout << "-->" << val << std::endl; std::string str; Deserialize(iss, str); std::cout << "-->" << str << std::endl; std::list<int> s; Deserialize(iss, s); for (auto item : s) { std::cout << item << std::endl; } std::map<std::string, int> m; Deserialize(iss, m); for (auto item : m) { std::cout << item.first << "-->" << item.second << std::endl; } std::tuple<int, std::string, double> tp; Deserialize(iss, tp); std::cout << std::get<0>(tp) << "-->" << std::get<1>(tp) << "-->" << std::get<2>(tp) << std::endl; std::set<int> st; Deserialize(iss, st); for (auto item : st) { std::cout << item << std::endl; } std::vector<MyTest> vecVal; Deserialize(iss, vecVal); for(auto item : vecVal) { std::cout << "age:" << *item.p << " name:" << item.name << std::endl; } } int main() { //序列化 std::vector<std::string> d = { "10","20","50","100","1000" }; std::ostringstream oss; Serialize(oss, d); Serialize(oss, 10); std::string str("hello"); Serialize(oss, str); std::list<int> s = { 10,20,50,100,1000 }; Serialize(oss, s); std::map<std::string, int> val = { { "1",3 }, { "3",4 }, {"6",8} }; Serialize(oss, val); std::tuple<int, std::string, double> tp{ 0, "test", 1.3 }; Serialize(oss, tp); std::vector<MyTest> vecVal = {MyTest(35, "hello"), MyTest(40, "world")}; std::set<int> st = { 100,30,70 }; Serialize(oss, st); Serialize(oss, vecVal); print(oss.str()); return 0; }
输出:code
实现过程对象
利用C++模板能够大大简化处理过程,第一步咱们须要对C++经常使用类型进行分类,而后结合C++泛型编程分步实现。blog
经常使用类型分类:内存
一、可平凡复制类型 (C++ POD概念,支持按位复制的类型)get
二、std::string 最经常使用类型,虽然string是能够自动分配内存的,但能够针对连续内存的特性进行特化处理。string
三、容器类型,须要支持容器嵌套处理
四、std::pair类型,多值结构须要特殊处理
五、std::tuple 元组不一样于其它C++容器,须要特殊处理。
如下位序列化代码:
//可平凡复制 template <typename T, typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type N = 0> void Serialize(std::ostream & os, const T & val) { os.write((const char *)&val,sizeof(T)); } //pair template <typename K, typename V> void Serialize(std::ostream & os, const std::pair<K, V> & val) { Serialize(os, val.first); Serialize(os, val.second); } // std::string void Serialize(std::ostream & os, const std::string &val) { size_t size = val.size(); os.write((const char *)&size, sizeof(size)); os.write((const char *)val.data(), size * sizeof(typename std::string::value_type)); } //容器 template <typename T, typename std::enable_if< std::is_same<typename std::iterator_traits<typename T::iterator>::value_type, typename T::value_type>::value , int>::type N = 0> void Serialize(std::ostream & os, const T & val) { size_t size = val.size(); os.write((const char *)&size, sizeof(size_t)); for (auto & v : val) { Serialize(os, v); } } //tuple template<typename T> int _Serialize(std::ostream & os, T& val) { Serialize(os, val); return 0; } template<typename Tuple, std::size_t... I> void _Serialize(std::ostream & os, Tuple& tup, std::index_sequence<I...>) { std::initializer_list<int>{_Serialize(os, std::get<I>(tup))...}; } template <typename...Args> void Serialize(std::ostream & os, const std::tuple<Args...>& val) { _Serialize(os, val, std::make_index_sequence<sizeof...(Args)>{}); }
反序列化
// 可平凡复制 template <typename T,typename std::enable_if<std::is_trivially_copyable<T>::value, int>::type N = 0> void Deserialize(std::istream & is, T & val) { is.read((char *)&val, sizeof(T)); } // std::string void Deserialize(std::istream & is, std::string &val) { size_t size = 0; is.read((char*)&size, sizeof(size_t)); val.resize(size); auto count = size * sizeof(typename std::string::value_type); is.read((char *)val.data(), count); } //pair template <typename V> struct ImpDeserialize { template<typename T> static void get(std::istream & is, T & val) { size_t size = 0; is.read((char *)&size, sizeof(size_t)); for (size_t i = 0; i < size; i++) { V v; Deserialize(is, v); val.insert(val.end(), v); } } }; template <typename K, typename V> struct ImpDeserialize<std::pair<K, V>> { template<typename T> static void get(std::istream & is, T & val) { size_t size = 0; is.read((char *)&size, sizeof(size_t)); for (size_t i = 0; i < size; i++) { K k; V v; Deserialize(is, k); Deserialize(is, v); val.emplace(k, v); } } }; // 容器 template <typename T, typename std::enable_if< std::is_same<typename std::iterator_traits<typename T::iterator>::value_type, typename T::value_type>::value , int>::type N = 0> void Deserialize(std::istream & is, T & val) { ImpDeserialize<typename T::value_type>::get(is, val); } //tuple template<typename T> int _Deserialize(std::istream & is, T& val) { Deserialize(is, val); return 0; } template<typename Tuple, std::size_t... I> void _Deserialize(std::istream & is, Tuple& tup, std::index_sequence<I...>) { std::initializer_list<int>{_Deserialize(is, std::get<I>(tup))...}; } template <typename...Args> void Deserialize(std::istream & is, std::tuple<Args...>& val) { _Deserialize(is, val, std::make_index_sequence<sizeof...(Args)>{}); }