转载请标明原文地址:https://segmentfault.com/a/11...
简介
LiteByte是一种轻量级的二进制数据交换格式。
体积小巧、简单易用是设计目标。主要用于解决前后台数据传输的问题。
作者:冰封百度(ZhangYu)
设计的灵感来源于C# struct内存对齐后的紧凑格式。
Gitee:https://gitee.com/zhangyu800/...
特点
1.紧凑的二进制数据格式,支持变长整型,数据量小。
2.用类定义对象结构,使用方便。
实现思路
把一个对象分为两个部分:结构和值。
结构用类定义,越方便越好。
值用于网络传输,越小越好。
// 比如像这样的对象 拆分成结构和值
public class UserInfo {
public int id = 1001;
public string name = "冰封百度";
}
// ↙ ↘
// 结构 // 值
public class SUserInfo {
public int id; // 1001 = [0x02, 0xE9, 0x03]
public string name; // "冰封百度" = [0x00, 0x05, 0xB0, 0x51, 0x01, 0x5C, 0x7E, 0x76, 0xA6, 0x5E]
}
// 对象的值就是:[0x02, 0xE9, 0x03, 0x05, 0xB0, 0x51, 0x01, 0x5C, 0x7E, 0x76, 0xA6, 0x5E]
前后台依赖相同的结构类,转换时把对象的值拆出来传输,解析时把值还原成对象。
测试Demo
链接:https://pan.baidu.com/s/18fbL...
使用方法
1.创建自定义结构类(UserInfo)。
2.添加using LiteByte 用[LBMember]标记要序列化的字段/属性。
3.调用LBUtil.Serialize(instance) 把对象序列化成二进制数据。
4.调用LBUtil.Deserilize<T>(bytes) 把二进制数据反序列化成对象。
代码样例:
// 1.自定义对象结构类:
// 2.using LiteByte
// 3.用LBMember标记要序列化的字段或属性
using System;
using LiteByte;
using System.Collections.Generic;
/// <summary> 玩家信息测试 | PlayerInfo test </summary>
public class STPlayerInfo {
[LBMember(0)]
public uint id;
[LBMember(1)]
public string nickname;
[LBMember(2)]
public byte gender;
[LBMember(3)]
public bool isVip;
[LBMember(4, LBTypeCode.VarInt32)]
public int lv;
[LBMember(5)]
public int hp;
[LBMember(6)]
public int mp;
[LBMember(7, LBTypeCode.VarUnicode)]
public string desc;
[LBMember(8)]
public List<int> ids;
[LBMember(9)]
public Dictionary<int, string> dic;
[LBMember(10, LBTypeCode.ASCII, LBTypeCode.VarUnicode)]
public Dictionary<string, string> dic2;
}
// 序列化和反序列化:
public void PlayerInfoTest() {
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "AAA");
dic.Add(2, "BBB");
Dictionary<string, string> dic2 = new Dictionary<string, string>();
dic2.Add("A", "ValueA");
dic2.Add("B", "ValueB");
STPlayerInfo st = new STPlayerInfo();
st.id = 100001;
st.nickname = "冰封百度";
st.gender = 1;
st.isVip = true;
st.lv = 999;
st.hp = 999999;
st.mp = 999999;
st.desc = "这是一个Demo";
st.ids = new List<int>() { 1, 2, 3, 4, 5 };
st.dic = dic;
st.dic2 = dic2;
// 序列化:
byte[] bytes = LBUtil.Serialize(typeName, player);
// 反序列化:
PlayerInfo info = LBUtil.Deserialize<PlayerInfo>(typeName, bytes);
// bytes长度:81字节
}
转换结果:
代码说明:
1.序列化对象:LBUtil.Serialize(obj)
2.反序列化对象:LBUtil.Deserilize<T>(bytes)
3.可以转换自定义的class和struct 字段(属性)需要是public的
支持的数据类型
数据类型介绍:
1.基本的值类型:bool、byte、short、int、long、float、double等
2.字符串 string (支持ASCII、Unicode、UTF8、VarUnicode四种编码方式)
3.数组和List(int[] 或 List<int>这种)
4.字典(Dictionary<K,V>)
4.自定义类型(class或struct)
数据类型说明:
1.对bool型的支持最好,一个bool型只占1位(1/8个字节)。
2.支持变长整数(short、int、long、ushort、uint、ulong)
3.支持null值 (能空的类型string, array, object,都支持它们为空的情况)
4.建议在定义数据格式时,用尽量小的类型定义字段,这样序列化的数据体积会更小,如果懒得写,可以考虑使用变长数据。
5.支持自定义字符串编码格式 每个字段都可以自定义。
6.因为在编写变长数据类型的过程中用到了一些不常见的数据格式,为了重用类型,索性就一起支持了,在对数据大小很严格的环境会有帮助。
基本数据类型
比特型(7种)
类型 | 长度 | 值范围 |
---|---|---|
Bit1(Boolean) | 1位 | 0 ~ 1 |
Bit2(Byte) | 2位 | 0 ~ 3 |
Bit3(Byte) | 3位 | 0 ~ 7 |
Bit4(Byte) | 4位 | 0 ~ 15 |
Bit5(Byte) | 5位 | 0 ~ 31 |
Bit6(Byte) | 6位 | 0 ~ 63 |
Bit7(Byte) | 7位 | 0 ~ 127 |
整型(16种)
类型 | 长度 | 值范围 |
---|---|---|
Int8(sbyte) | 1字节 | -128 ~ 127 |
Int16(short) | 2字节 | -32768 ~ -32767 |
Int24(int) | 3字节 | -8388608 ~ 8388607 |
Int32(int) | 4字节 | -2147483648 ~ 2147483647 |
Int40(long) | 5字节 | -549755813888 ~ 549755813887 |
Int48(long) | 6字节 | -140737488355328 ~ 140737488355327 |
Int56(long) | 7字节 | -36028797018963968 ~ 36028797018963967 |
Int64(long) | 8字节 | -9223372036854775808 ~ 9223372036854775807 |
UInt8(byte) | 1字节 | 0 ~ 255 |
UInt16(ushort) | 2字节 | 0 ~ 65535 |
UInt24(uint) | 3字节 | 0 ~ 16777215 |
UInt32(uint) | 4字节 | 0 ~ 4294967295 |
UInt40(ulong) | 5字节 | 0 ~ 1099511627775 |
UInt48(ulong) | 6字节 | 0 ~ 281474976710655 |
UInt56(ulong) | 7字节 | 0 ~ 72057594037927935 |
UInt64(ulong) | 8字节 | 0 ~ 18446744073709551615 |
浮点型(5种)
类型 | 长度 | 有效数字 | 值范围 |
---|---|---|---|
Float8(float) | 1字节 | 7位 | 0/255 ~ 255/255 |
Float16(float) | 2字节 | 3位 | ±6.55E +4 |
Float24(float) | 3字节 | 5位 | ±1.8447E +19 |
Float32(float) | 4字节 | 7位 | ±3.402823E +38 |
Float64(double) | 8字节 | 15位 | ±1.7976931348623157E +308 |
变长整型(7种)
类型 | 长度 | 值范围 |
---|---|---|
VarInt16(short) | 1位 + 1~2字节 | 同Int16 |
VarInt32(int) | 2位 + 1~4字节 | 同Int32 |
VarInt64(long) | 3位 + 1~8字节 | 同Int64 |
VarUInt16(ushort) | 1位 + 1~2字节 | 同UInt16 |
VarUInt32(uint) | 2位 + 1~4字节 | 同UInt32 |
VarUInt64(ulong) | 3位 + 1~8字节 | 同UInt64 |
VarLength(int) | 3位 + 1~8字节 | -1 ~ (Int32.MaxValue/2 - 1) |
字符串(4种编码)
类型 | 单个字符长度 | 总长度范围 |
---|---|---|
UTF8(string) | 1~4字节 | 头(1~4)字节+体(0 ~ 1073741822)字节 |
Unicode(string) | 2字节 | 头(1~4)字节+体(0 ~ 1073741822)x2字节 |
ASCII(string) | 1字节 | 头(1~4)字节+体(0 ~ 1073741822)字节 |
VarUnicode(string) | 1~4字节 | 同VarLength + VarUInt32 |
复杂数据类型(4种)
类型 | 表达式 |
---|---|
数组 | T[] |
列表 | List<T> |
字典 | Dictionary<T, V> |
自定义类型 | class Name{} |
更新日志:
0.7.0: 用IL.Emit代替反射,大幅度提升get和set性能 IL优化后性能比直接=稍慢大概一倍,优化之前反射比直接=慢几十倍。
0.8.0: 添加编译多个类的功能,一个配置文件可以写多个类了,可以一次性识别。
0.8.1:删除LBObject类,因为IL优化后get和set的性能很好,不再需要LBObject了。
0.8.2:优化LBParser中 从tokens中删除访问修饰符的代码,不再生成新的list。
0.8.3:优化反射工具类 ReflectionUtil 创建实例方法中的参数
0.9.0: 优化反射工具(增加IL.Emit工具、委托工具、指针工具 用于优化反射) 增加反射工具对IL2CPP模式的兼容性
0.10.0: 重构LBReader读取类 增加对List的支持 优化LBConverter类
0.10.1: 修复BUG:1.LBWriter WriteVarLength时没有正确扩容的BUG 2.LBConverter没有正确抛出错误信息的BUG
0.11.0: 重构LBWriter写入类 增加对List的支持 优化LBConverter类
0.11.1: 优化LBConverter.ToObject() 和 ToBytes()
0.12.0:重构序列化/反序列化方式 不再使用配置文件 直接使用类+属性标签的方式完成,删除读配置文件的所有功能。增加对List<T>和Dictionary<K,V>的支持。
其他说明:
由于能力有限,暂时只实现了C#版本(在Unity中实现的,算半个.Net吧)
其他语言后续有时间再写,虽然造了个轮子 不过感觉造轮子的过程中收获远大于付出,挺开心的。
建了个群,有需求的可加。
QQ群:715800513
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。