LiteByte 二进制数据交换格式

转载请标明原文地址:https://segmentfault.com/a/1190000021329368

一、简介

icon_1_alpha_256x72.png
LiteByte是一种轻量级的二进制数据交换格式。
体积小巧、简单易用是设计目标,主要用于解决前后台数据传输的问题。

版本:0.13.2
作者:冰封百度(ZhangYu)
设计的灵感来源于C# struct内存对齐后的紧凑格式。

Gitee:https://gitee.com/zhangyu800/litebyte

1.特点

1.紧凑的二进制数据格式,支持变长整型,数据量小。
2.自定义类型文件,使用方便。

2.实现思路

把一个对象分为两个部分:结构和值。
结构用文本定义,越方便越好。
值用于网络传输,越小越好。

			 // 比如像这样的对象 拆分成结构和值两部分
             public class User {

                 public int id = 1001;
                 public string name = "冰封百度";

             }

//              ↙              ↘
// 结构                           // 值
public class User {       

    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]

前后台依赖相同的结构体文本,转换时把对象的值拆出来传输,解析时把值还原成对象。

3.支持的数据类型

一、基本数据类型(27种)
	1.整数类型:
		(01)bit1(bool);      1位定长无符号整数 取值范围:[0 = false1 = true]
		(02)char:           16位定长无符号整数 取值范围:[0 ~ 65535]
		(03)int8(sbyte):     8位定长有符号整数 取值范围:[-128 ~ 127]
		(04)int16:          16位定长有符号整数 取值范围:[-32768 ~ 3276]
		(05)int32:          32位定长有符号整数 取值范围:[-2147483648 ~ 2147483647]
		(06)int64:          64位定长有符号整数 取值范围:[-9223372036854775808 ~ 9223372036854775807]
		(07)uint8(byte):	 8位定长无符号整数 取值范围:[0 ~ 255]
		(08)uint16:         16位定长无符号整数 取值范围:[0 ~ 65535]
		(09)uint32:         32位定长无符号整数 取值范围:[0 ~ 4294967295]
		(10)uint64:         64位定长无符号整数 取值范围:[0 ~ 18446744073709551615]
		(11)vint16(short):  1+(8~16)位变长有符号整数 取值范围:同int16
		(12)vint32(int):    2+(8~32)位变长有符号整数 取值范围:同int32
		(13)vint64(long):   3+(8~64)位变长有符号整数 取值范围:同int64
		(14)vuint16(ushort):1+(8~16)位变长无符号整数 取值范围:同uint16
		(15)vuint32(uint):  2+(8~32)位变长无符号整数 取值范围:同uint32
		(16)vuint64(ulong): 3+(8~64)位变长无符号整数 取值范围:同uint64
	2.浮点数:
		(17)float8:          8位定长浮点数 取值范围:[0/255 ~ 255/255]
		(18)float16(half):  16位定长浮点数 取值范围:[-65504 ~ 65504]
		(19)float32(float): 32位定长浮点数 取值范围:[-3.40282347E+38F ~ 3.40282347E+38F]
		(20)float64(double):64位定长浮点数 取值范围:[-1.7976931348623157E+308 ~ 1.7976931348623157E+308]
		(21)decimal:		 vuint32 + (4 x n)位变长浮点数 取值范围:[-a.b ~ a.b](decimal转为字符串)
	3.字符串:
		(22)ascii:           vuint32 x 8位定长字符串
		(23)utf8:            vuint32 x (8~32) 变长字符串
		(24)utf16:           vuint32 x (16~32) 变长字符串
		(25)utf32:           vuint32 x 32位 定长字符串(with BOM)
		(26)vunicode(string):vuint32 x vuint32 变长字符串
	4.日期时间
		(27)DateTime:        vuint64(8~64)位变长整数(转为Java timestamp毫秒)
——————————————————————————————————————————————————————————————————
二、特殊数据类型(3)
	1.数组   Array(int[]、long[]、string[] 等)
	2.列表   List<T>(List<int>、List<long>、List<string> 等)
	3.哈希表 Dictionary<TKey, TValue>(Dictionary<int, int>、Dictionary<string, string> 等)
——————————————————————————————————————————————————————————————————
三、自定义数据类型(有默认构造函数的 非泛型)
	1.class类(默认值为null):
		public class UserVO {

			public int id;
			public string name;

		}
	2.struct结构体(有默认值 不为null):
		public struct Vector3VO {

			public float x;
			public float y;
			public float z;

		}

4.不支持的数据类型

1.无默认构造函数的自定义类型(需要传参数初始化的自定义类型)
2.带泛型的自定义类型(初始化时需要传泛型的)
3.循环引用的类型(比如LinkedListNode 有Previous和Next引用会导致对象被循环引用 无法初始化)

二、使用方法

1.创建自定义类型文本文件(ClassTestVO.txt)。
2.创建自定义类(ClassTestVO.cs)
3.使用LBUtil.LoadClasses(["class1", "class2"])加载自定义类型文件内容。
4.使用LBUtil.Serialize(obj, "ClassTestVO") 把对象序列化成二进制数据。
5.使用LBUtil.Deserilize(bytes, "ClassTestVO") 把二进制数据反序列化成对象。

1.创建自定义类型文本

创建一个自定义类型文件 ClassTestVO.txt 内容如下:

/// <summary> 自定义类型测试 </summary>
public class ClassTestVO {

    public bool boolValue;
    public char charValue;
	public byte byteValue;
    public sbyte sbyteValue;
    public short shortValue;
    public ushort ushortValue;
    public int intValue;
    public uint uintValue;
    public long longValue;
    public ulong ulongValue;
    public float floatValue;
    public double doubleValue;
	public decimal decimalValue;
	public DateTime dateTime;
    public string stringValue;
    public int[] array;
    public List<int> list;
    public Dictionary<string, string> map;
    public IDCard classObject;
    public Position structObject;
	public EmptyVO emptyObject;

}

/// <summary> 身份证信息 </summary>
public class IDCard {

    public string id;
    public string name;
    public int age;
    public int gender;
    public string address;

}

/// <summary> 位置信息 </summary>
public struct Position {

    public float x;
    public float y;
    public float z;

}

/// <summary> 没任何成员的对象 </summary>
public class EmptyVO {
	
}

2.创建自定义类

创建 ClassTestVO.txt 对应的 ClassTestVO.cs 内容如下:

namespace LiteByte.Test {

    /// <summary>
    /// <para>Class测试</para>
    /// 字段和属性(get; set;)都支持. null对象也支持
    /// </summary>
    public class ClassTestVO {

        // Field和Property写法都支持 class类型可以为null struct类型不支持为null
        // public string name;
        // public string name { get; set; }
        public bool boolValue;
        public char charValue;
        public byte byteValue;
        public sbyte sbyteValue;
        public short shortValue;
        public ushort ushortValue;
        public int intValue;
        public uint uintValue;
        public long longValue;
        public ulong ulongValue;
        public float floatValue;
        public double doubleValue;
        public decimal decimalValue;
        public DateTime dateTime;
        public string stringValue;
        public int[] array;
        public List<int> list;
        public Dictionary<string, string> map;
        public IDCard classObject;
        public Position structObject;
        public EmptyVO emptyObject;

    }

    /// <summary> 身份证信息 </summary>
    public class IDCard {

        public string id;
        public string name;
        public int age;
        public int gender;
        public string address;

        public IDCard() { }

        public IDCard(string id, string name, int age, int gender, string address) {
            this.id = id;
            this.name = name;
            this.age = age;
            this.gender = gender;
            this.address = address;
        }

        public override string ToString() {
            string _id = id == null ? "null" : id;
            string _name = name == null ? "null" : name;
            string _address = address == null ? "null" : address;
            return $"{{{_id}, {_name}, {age}, {gender}, {_address}}}";
        }

    }

    /// <summary> 位置信息 </summary>
    public struct Position {

        public float x;
        public float y;
        public float z;

        public Position() { }

        public Position(float x, float y, float z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        override public string ToString() {
            return $"({x}, {y}, {z})";
        }

    }

    /// <summary> 没任何成员的对象 </summary>
    public class EmptyVO {

    }

}

3.加载自定义类型文件

使用 LBUtil.LoadClasses(["classText1", "classText2"]) 加载自定义类型文件内容

// 加载自定义类型
private static void LoadClasses() {
    string root = "Resources/LBTypes/";
    string[] files = { "ClassTestVO.txt" };
    string[] codes = new string[files.Length];
    for (int i = 0; i < files.Length; i++) {
        string url = root + files[i];
        string text = File.ReadAllText(url, Encoding.UTF8);
        codes[i] = text;
    }
    LBUtil.LoadClasses(codes);
}

4.序列化对象

使用 LBUtil.Serialize(obj, "ClassTestVO") 把对象序列化成二进制数据。

private static void ClassTest() {
    // Serialize
    ClassTestVO vo = new ClassTestVO() {
        boolValue = true,
        charValue = 'a',
        byteValue = byte.MaxValue,
        sbyteValue = sbyte.MinValue,
        shortValue = short.MinValue,
        ushortValue = ushort.MaxValue,
        intValue = 10086,
        uintValue = 68001,
        longValue = long.MinValue,
        ulongValue = ulong.MaxValue,
        floatValue = -123.456f,
        doubleValue = 12345.1234567890,
        decimalValue = -1234567890.0123456789m,
        dateTime = DateTime.Now,
        stringValue = "asdf1234",
        array = new int[] { 1, 2, 3, 4, 5 },
        list = new List<int>() { 10, 11, 12, 13, 14 },
        map = new Dictionary<string, string>() { { "a", "ABC" }, { "b", "BCD" }, { "c", "CDE" } },
        classObject = new IDCard("123456YYYYMMDD123X", "张三", 18, 1, "地球村"),
        structObject = new Position(1.1f, 1.2f, 1.3f),
        emptyObject = new EmptyVO()
    };
    byte[] bytes = LBUtil.Serialize(vo, "ClassTestVO");

    // Deserialize
    ClassTestVO _vo = LBUtil.Deserialize<ClassTestVO>(bytes, "ClassTestVO");
    string json = JsonSerializer.Serialize(_vo, jsonOptions);
    Trace.WriteLine($"ClassTest() LBSize:{bytes.Length} JsonSize:{json.Length} json:\n{json}");
	/*
	输出:
	ClassTest() LBSize:165 JsonSize:617 json:
{"boolValue":true,"charValue":"a","byteValue":255,"sbyteValue":-128,"shortValue":-32768,"ushortValue":65535,"intValue":10086,"uintValue":68001,"longValue":-9223372036854775808,"ulongValue":18446744073709551615,"floatValue":-123.456,"doubleValue":12345.123456789,"decimalValue":-1234567890.0123456789,"dateTime":"2025-02-27T14:38:22.217","stringValue":"asdf1234","array":[1,2,3,4,5],"list":[10,11,12,13,14],"map":{"a":"ABC","b":"BCD","c":"CDE"},"classObject":{"id":"123456YYYYMMDD123X","name":"\u5F20\u4E09","age":18,"gender":1,"address":"\u5730\u7403\u6751"},"structObject":{"x":1.1,"y":1.2,"z":1.3},"emptyObject":{}}
*/
}

5.反序列化对象

使用 LBUtil.Deserilize<ClassTestVO>(bytes, "ClassTestVO") 把二进制数据反序列化成对象

// Deserialize
ClassTestVO _vo = LBUtil.Deserialize<ClassTestVO>(bytes, "ClassTestVO");

三、更新日志:

0.7.0:  用IL.Emit代替反射,大幅度提升getset性能。
0.8.0:  添加编译多个类的功能,一个配置文件可以写多个类了,可以一次性识别。
0.8.1:  删除LBObject类,因为IL优化后getset的性能很好,不再需要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: 精简代码 增加LBWriter和LBReader的代码重用性。
0.13.0: 重写LBLexer、LBParser、LBWriter、LBReader、LBConverter 全面改进用法 提升便捷性
0.13.1: 重写LBReflectionUtil、LBMemberWrapper 用指针替代Field的反射、用Delegate替代Property的反射 提升性能
0.13.2: 增加对decimal、DateTime类型的支持。重写WriteBits()、ReadBits()方法, 添加LBTest测试类。

四、其他说明:

由于能力有限,暂时只实现了C#(.Net)版本
其他语言后续有时间再写,虽然造了个轮子,不过感觉造轮子的过程中收获远大于付出,挺开心的。
建了个群,有需求的可加。
QQ群:715800513

posted @   冰封百度  阅读(541)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示