## 序列化定义
在编写程序过程中往往需要将某些数据存储到内存中,然后将其写入文件或通过网络传输到另一台计算机实现通信。这个将数据转化成能够存储或传输格式的过程被称为序列化,而其逆过程则被称为反序列化。
详细来说,序列化是将对象实例的状态转换为可存储或传输格式的过程,反序列化是依据存储或传输的内容重构对象,两者结合起来,能轻松进行数据存储和数据传输。比如,序列化一个对象,然后使用http通过Internet在client和server之间传输。简言之:
* 序列化:将对象变成字节流。
* 反序列化:从字节流恢复成原来的对象。
## 序列化实现
在C++中,常用的序列化工具有Json,XML和protobuf等,但用这些工具的时候都需要依赖相应的库,相对来说比较麻烦。为了理解序列化过程和可以不依赖其他库实现一些简单的序列化功能,用C++实现一个简单的序列化工具,代码只有一百多行。实现参考[https://github.com/button-chen/buttonrpc\_cpp14](https://github.com/button-chen/buttonrpc_cpp14)
```
/**
* 序列化反序列化
* 仅支持原生类型的数据结构,不支持含有指针的数据结构
*/
#ifndef SERIALIZER_H
#define SERIALIZER_H
#include <vector>
#include <algorithm>
// 存储数据流的容器
class StreamBuffer : public std::vector<char> {
public:
StreamBuffer() : curpos_(0) {}
StreamBuffer(const char* s, size_t len) : curpos_(0)
{
insert(begin(), s, s + len);
}
const char* data() { return &(*this)[0]; }
const char* curdata() { return &(*this)[curpos_]; }
size_t cursize() const { return size() - curpos_; }
bool eof() const { return curpos_ >= size(); }
void offset(int k) { curpos_ += k; }
void input(const char* s, size_t len) { insert(end(), s, s + len); }
void reset() { curpos_ = 0; }
private:
size_t curpos_;
};
class Serializer {
public:
enum ByteOrder
{
BigEndian, // 大端
LittleEndian // 小端
};
public:
Serializer() : byteOrder_(LittleEndian) {}
Serializer(StreamBuffer s, int byteOrder = LittleEndian)
: streamBuffer_(s), byteOrder_(byteOrder) {}
template <typename T>
void input_type(T t);
template <typename T>
void output_type(T& t);
template<typename Tuple, std::size_t Id>
void getv(Serializer& ds, Tuple& t) {
ds >> std::get<Id>(t);
}
void reset(){
streamBuffer_.reset();
}
void clear()
{
streamBuffer_.clear();
reset();
}
void input(const char* data, int len)
{
streamBuffer_.input(data, len);
}
template<typename Tuple, std::size_t... I>
Tuple get_tuple(std::index_sequence<I...>) {
Tuple t;
((getv<Tuple, I>(*this, t)), ...);
return t;
}
template<typename T>
Serializer& operator >> (T& i)
{
output_type(i);
return *this;
}
template<typename T>
Serializer& operator << (T i)
{
input_type(i);
return *this;
}
const char* data() { return streamBuffer_.curdata(); }
size_t size() const { return streamBuffer_.cursize(); }
private:
void byte_order(char* s, int len)
{
if (byteOrder_ == BigEndian)
std::reverse(s, s + len);
}
private:
int byteOrder_;
StreamBuffer streamBuffer_;
};
template <typename T>
inline void Serializer::input_type(T t)
{
int len = sizeof(T);
char* d = new char[len];
const char* p = reinterpret_cast<const char*>(&t);
memcpy(d, p, len);
byte_order(d, len);
streamBuffer_.input(d, len);
delete[] d;
}
// 偏特化
template <>
inline void Serializer::input_type(std::string t)
{
// 先存入字符串长度
uint16_t len = t.size();
char* p = reinterpret_cast<char*>(&len);
byte_order(p, sizeof(uint16_t));
streamBuffer_.input(p, sizeof(uint16_t));
// 存入字符串
if (len == 0) return;
char* d = new char[len];
memcpy(d, t.data(), len);
byte_order(d, len);
streamBuffer_.input(d, len);
delete[] d;
}
template<>
inline void Serializer::input_type(const char* in)
{
input_type<std::string>(std::string(in));
}
template <typename T>
inline void Serializer::output_type(T& t)
{
int len = sizeof(T);
char* d = new char[len];
if (!streamBuffer_.eof())
{
memcpy(d, streamBuffer_.curdata(), len);
streamBuffer_.offset(len);
byte_order(d, len);
t = *reinterpret_cast<T*>(&d[0]);
}
delete[] d;
}
// 偏特化
template <>
inline void Serializer::output_type(std::string& t)
{
// 先取字符串长度
int strlen = sizeof(uint16_t);
char* d = new char[strlen];
memcpy(d, streamBuffer_.curdata(), strlen);
byte_order(d, strlen);
streamBuffer_.offset(strlen);
int len = *reinterpret_cast<uint16_t*>(&d[0]);
delete[] d;
// 再取字符串
if (len == 0) return;
t.insert(t.begin(), streamBuffer_.curdata(), streamBuffer_.curdata() + len);
streamBuffer_.offset(len);
}
#endif
```
## 验证
```
#include <iostream>
#include "serializer.h"
using namespace std;
struct S {
S() {}
S(int i, float f) : a(i), b(f) {}
int a;
float b;
friend ostream &operator<<(ostream &os, const S &s);
};
ostream &operator<<(ostream &os, const S &s)
{
return os << s.a << ", " << s.b;
}
int main()
{
Serializer serializer;
string str = "abcdef";
int n = 10;
S s(7, 11.2);
serializer.input_type(str);
serializer.input_type(n);
serializer.input_type(s);
string got_str;
int got_n;
S got_s;
serializer.output_type(got_str);
serializer.output_type(got_n);
serializer.output_type(got_s);
cout << "got_str: " << got_str << endl;
cout << "got_n: " << got_n << endl;
cout << "got_s: " << got_s << endl;
}
```
输出结果:
```
got_str: abcdef
got_n: 10
got_s: 7, 11.2
```
- 空白目录
- 算法
- 排序
- 冒泡排序
- 选择排序
- 插入排序
- 归并排序
- 快速排序
- 计数排序
- 桶排序
- 基数排序
- 希尔排序
- 堆排序
- 二分查找
- 最小堆
- 最小索引堆
- 平衡二叉树(AVL tree)
- bitmap位图
- 布隆过滤器
- hashmap
- topK
- 跳表
- LRU Cache
- kmp
- 最小堆和堆排序
- 最短路径
- C++
- 运行时类型判断RTTI
- C++反射
- 手动实现智能指针
- 序列化实现
- rpc实现
- std::forward
- 函数指针的妙用
- C/C++
- std::function
- 同步队列
- 线程池实现
- std::promise
- 深入理解虚函数
- extern "C" 关键字讲解
- 大端小端的区别
- 简历
- 简历1
- redis
- 数据结构和对象
- sds
- list
- zskiplist
- 腾讯云redis面试题总结
- redis集群部署
- LeetCode
- 目标
- go基础
- 算法快速入门
- 数据结构篇
- 二叉树
- 链表
- 栈和队列
- 二进制
- 基础算法篇
- 二分搜索
- 排序算法
- 动态规划
- 算法思维
- 递归思维
- 滑动窗口思想
- 二叉搜索树
- 回溯法
- 其他
- 剑指offer
- 笔记
- git代理加速
- Linux
- vim大法
- vscode远程不能跳转
- cmake
- 设计模式
- 单例模式
- 简单工厂模式
- 外观模式
- 适配器模式
- 工厂方法模式
- 抽象工厂模式
- 生成器模式
- 原型模式
- 中介者模式
- 观察者模式
- 访问者模式
- 命令模式
- 网络编程
- epoll reactor模式
- linux timerfd系列函数总结
- IO
- mapreduce
- 反射器
- leo通信库
- Mutex
- Condition
- thread
- raft
- 协程
- hook
- 定时器
- 别人的面试经验
- 面试题
- vector崩溃问题
- JAVA
- Linux java环境配置
- ucore
- lab1
- FreeNOS
- leveldb
- 刷题笔记
- 回文串
- 前缀树
- 字符串查找
- 查找两个字符串a,b中的最长公共子串
- 动态规划
- golang
- 顺序循环打印实现
- 数据结构
- rpc运用
- python
- 单例
- 深拷贝浅拷贝
- 链表
- python基础题
- mysql
- 事务
- Linux
- 共享内存
- 刷题记录
- 贪心算法
- 动态规划
- 面试
- 腾讯C++面试
- 微众面试JD
- 迅雷网络面试
- 学习网址
- rabbitMq
