共享Windows下C++库之序列化组件

来源:互联网 发布:递归算法的使用场景 编辑:程序博客网 时间:2024/05/01 11:31

简介:

什么是序列化?简单来说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻松地存储和传输数据。

对象序列化反序列化通常用于:

1. 将对象存储于硬盘上

2. 在网络上传送对象的字节序列

这是一个简易的序列化组件,代码不足500行,支持对内置类型、用户自定义类型、STL容器。

这里是介绍序列化的Wiki。

这里是boost的序列化库。

这里是Protobuf,强烈建议没有学习过的同学研究下。

下载地址:

CSDN资源

特点:

    1. 接口简单,易于集成,方便维护。
    2. 基于Policy-based设计模式
    3. 采用C++流式方式方便易用
    4. 扩展性强(针对用户自定义类型,输出目标)
    5. 编译期对用户自定义类型侦错

目标:

    1. 客户端代码接口简洁,使用户代码短小便捷(满足)
    2. 指针的深度存储与恢复,保存指针所指内存或恢复数据到指针所指向区域,且能正确处理多个指针(满足)
    3. 对STL容器的支持,能正确处理嵌套容器(满足)
    4. 支持多种存储方式(目前仅支持文件与内存)
    5. 非入侵式实现,不需要从某个特定的类派生或实现特定的成员函数(需要友元函数或者另一个名字空间的自由函数)

内部原理:

未命名

Tutorial:

1. 基础数据测试,char类型数据内存缓冲区,写入任意类值类型数据,再重新冲读取,判断值是否一致

 

void TestBasic(){char buf[1024] = {0};utility::serialize::Serialize os(buf);int b1 = 1;long b2 = 1L;long long b3 = 1LL;double b4 = 1.111;char b5 = 'a';char b6[] = "bc";wchar_t b7 = L'c';wchar_t b8[] = L"Yu";os << b1;os << b2;os << b3;os << b4;os << b5;os << b6;os << b7;os << b8;std::string b9("测试1");std::wstring b10(L"测试2");os << b9;os << b10;char *b11 = "asd";wchar_t *b12 = L"bbb";os << b11 << b12;utility::serialize::Serialize in(buf);int a1 = 0;long a2 = 0L;long long a3 = 0LL;double a4 = 0.0;char a5 = 0;char a6[1024] = {0};wchar_t a7 = L'';wchar_t a8[1024] = {0};std::string a9;std::wstring a10;in >> a1;in >> a2;in >> a3;in >> a4;in >> a5;in >> a6;in >> a7;in >> a8;in >> a9;in >> a10;char tmp1[4] = {0};wchar_t tmp2[4] = {0};char *a11 = tmp1;wchar_t *a12 = tmp2;in >> a11 >> a12;assert(b1 == a1);assert(b2 == a2);assert(b3 == a3);assert(b4 == a4);assert(b5 == a5);assert(strcmp(b6, a6) == 0);assert(b7 == a7);assert(wcscmp(b8, a8) == 0);assert(b9 == a9);assert(b10 == a10);assert(strcmp(b11, a11) == 0);assert(wcscmp(b12, a12) == 0);}


2. 基础数据测试,wchar_t类型数据内存缓冲区,测试目的与测试样例1相同

 

void TestUnicode(){wchar_t buf[1024] = {0};utility::serialize::SerializeW os(buf);int b1 = 1;long b2 = 1L;long long b3 = 1LL;double b4 = 1.111;char b5 = 'a';char b6[] = "bc";wchar_t b7 = L'c';wchar_t b8[] = L"Yu";os << b1;os << b2;os << b3;os << b4;os << b5;os << b6;os << b7;os << b8;std::string b9("测试1");std::wstring b10(L"测试2");os << b9;os << b10;char *b11 = "asd";wchar_t *b12 = L"bbb";os << b11 << b12;utility::serialize::SerializeW in(buf);int a1 = 0;long a2 = 0L;long long a3 = 0LL;double a4 = 0.0;char a5 = 0;char a6[1024] = {0};wchar_t a7 = L'';wchar_t a8[1024] = {0};std::string a9;std::wstring a10;in >> a1;in >> a2;in >> a3;in >> a4;in >> a5;in >> a6;in >> a7;in >> a8;in >> a9;in >> a10;char tmp1[4] = {0};wchar_t tmp2[4] = {0};char *a11 = tmp1;wchar_t *a12 = tmp2;in >> a11 >> a12;assert(b1 == a1);assert(b2 == a2);assert(b3 == a3);assert(b4 == a4);assert(b5 == a5);assert(strcmp(b6, a6) == 0);assert(b7 == a7);assert(wcscmp(b8, a8) == 0);assert(b9 == a9);assert(b10 == a10);assert(strcmp(b11, a11) == 0);assert(wcscmp(b12, a12) == 0);}


3. 数组类型数据测试,针对数组提供单独测试用例

 

void TestArray(){char buf[1024] = {0};utility::serialize::Serialize os(buf);char a1[] = "1234";unsigned char a2[] = "QWER";short a3[] = {1, 2, 3, 4};int a4[] = {5, 6, 7, 8};long a5[] = {10, 10, 10, 10};unsigned long long a6[] = {100LL, 100LL, 100LL};os << a1;os << a2;os << a3 << a4 << a5 << a6;char b1[5] = {0};unsigned char b2[5] = {0};short b3[4] = {0};int b4[4] = {0};long b5[4] = {0};unsigned long long b6[3] = {0};os >> b1 >> b2 >> b3 >> b4 >> b5 >> b6;assert(strcmp(b1, a1) == 0);assert(memcmp(b2, a2, _countof(a2)) == 0);assert(memcmp(b3, a3, _countof(a3)) == 0);assert(memcmp(b4, a4, _countof(a4)) == 0);assert(memcmp(b5, a5, _countof(a5)) == 0);assert(memcmp(b6, a6, _countof(a6)) == 0);}


4.自定义数据类型测试,如果自定义数据(非POD类型数据)没有提供operator<<或operator>>,则由编译期错误

 

struct CustomType{int age_;TCHAR class_[64];std::wstring name_;CustomType(): age_(0){std::fill(class_, class_ + _countof(class_), 0);}CustomType(int age, LPCTSTR cla, LPCTSTR name): age_(age), name_(name){_tcscpy(class_, cla);}};bool operator==(const CustomType &lhs, const CustomType &rhs){return lhs.age_ == rhs.age_ && _tcscmp(lhs.class_, rhs.class_) == 0 &&lhs.name_ == rhs.name_;}utility::serialize::Serialize &operator<<(utility::serialize::Serialize &os, const CustomType &type){os << type.age_ << type.class_ << type.name_;return os;}utility::serialize::Serialize &operator>>(utility::serialize::Serialize &os, CustomType &type){os >> type.age_ >> type.class_ >> type.name_;return os;}void TestClass(){char buf[1024];CustomType customType(10, _T("一年级一班"), _T("王小五"));utility::serialize::Serialize os(buf);os << customType;CustomType dst1, dst2;os >> dst1;os << &customType;os >> dst2;CustomType arr[2] = {CustomType(10, _T("一年级一班"), _T("王小五")),CustomType(11, _T("2年级2班"), _T("王小2"))};os << arr;CustomType brr[2];os >> brr;assert(dst1 == customType); assert(dst2 == customType);for(size_t i = 0; i != _countof(arr); ++i){assert(arr[i] == brr[i]);}};


5. STL容器测试,支持嵌套容器的序列化

void TestContainer(){char buf[1024] = {0};utility::serialize::Serialize os(buf);std::vector<int> a1(10);std::fill(a1.begin(), a1.end(), 10);os << a1;std::vector<int> b1;os >> b1;assert(std::equal(a1.begin(), a1.end(), b1.begin()));std::list<std::string> a2;a2.push_back("chenyu");a2.push_back("test");os << a2;std::list<std::string> b2;os >> b2;assert(std::equal(a2.begin(), a2.begin(), b2.begin()));std::deque<std::wstring> a3;a3.push_back(L"test1");a3.push_back(L"test2");os << a3;std::deque<std::wstring> b3;os >> b3;assert(std::equal(a3.begin(), a3.begin(), b3.begin()));std::set<long> a4;a4.insert(1L);a4.insert(10L);a4.insert(100L);os << a4;std::set<long> b4;os >> b4;assert(std::equal(a4.begin(), a4.begin(), b4.begin()));std::map<std::string, long> a5;a5.insert(std::make_pair("123", 1L));a5.insert(std::make_pair("1234", 10L));a5.insert(std::make_pair("12345", 100L));os << a5;std::map<std::string, long> b5;os >> b5;assert(std::equal(a5.begin(), a5.begin(), b5.begin()));std::multiset<long> a6;a6.insert(1L);a6.insert(10L);a6.insert(10L);a6.insert(10L);a6.insert(100L);a6.insert(100L);os << a6;std::set<long> b6;os >> b6;assert(std::equal(a6.begin(), a6.begin(), b6.begin()));std::multimap<std::string, long> a7;a7.insert(std::make_pair("123", 1L));a7.insert(std::make_pair("123", 1L));a7.insert(std::make_pair("1234", 10L));a7.insert(std::make_pair("1234", 100L));a7.insert(std::make_pair("1234", 1000L));a7.insert(std::make_pair("12345", 100L));os << a7;std::multimap<std::string, long> b7;os >> b7;assert(std::equal(a7.begin(), a7.begin(), b7.begin()));typedef std::map<std::pair<std::string, long>, std::vector<std::wstring>> VecMap;VecMap a8;std::vector<std::wstring> vec;vec.push_back(L"Test");vec.push_back(L"asd");a8.insert(std::make_pair(std::make_pair("10", 10), vec));a8.insert(std::make_pair(std::make_pair("11", 101), vec));a8.insert(std::make_pair(std::make_pair("11", 1011), vec));os << a8;VecMap b8;os >> b8;assert(std::equal(a8.begin(), a8.begin(), b8.begin()));}

 

6. 基础数据测试,以File为缓冲区,类似测试样例1

void TestFile(){utility::serialize::FileSerialize file("test.txt");int a1 = 10;long a2 = 10L;char a3 = 'c';char a4[] = "chenyu";wchar_t a5[] = L"chenyu";file << a1 << a2 << a3 << a4 << a5;int b1 = 0;long b2 = 0L;char b3 = 0;char b4[1024] = {0};wchar_t b5[1024] = {0};file >> b1 >> b2 >> b3 >> b4 >> b5;assert(a1 == b1);assert(a2 == b2);assert(a3 == b3);assert(strcmp(a4, b4) == 0);assert(wcscmp(a5, b5) == 0);}


 

 

未来的版本变化:

  1. 缺乏多线程间同步支持,这个也是理念导致。窃以为,在序列化中,同步应该是用户层的事情,即需要用户指定是否需要同步。当然,也可以遵照policy-based的设计方式,提供模板参数,以达到编译器选择是否需要同步。
  2. 仅支持对象(包括内置类型)的序列化,不支持远程过程调用。以后也不考虑(复杂)
  3. 借鉴Protobuf与boost serialize的优势,本着简单易用小巧的原则扩展。

下载地址:

CSDN资源