CBOR 编解码
JSON 与 CBOR 互转,十六进制和 Base64 都能贴,标签、不定长和大整数会保留下来。
编码规则
第一个字节拆成高 3 位的主类型和低 5 位的附加信息。主类型 0 是无符号整数、1 是负整数、2 是字节串、3 是文本串、4 是数组、5 是 map、6 是标签、7 是简单值和浮点。附加信息小于 24 时直接就是值,24 到 27 表示后面跟着 1、2、4、8 字节的长度,31 表示不定长。
负整数存的是 -1 - n,所以 -1 的字节是 0x20,-2 是 0x21。这个约定和补码不同,直接按位读会算错,工具在解码时已经还原成真实的负数。
标签本身不改变数据的类型,只是补充语义。比如标签 0 后面必须跟一个符合 RFC 3339 的文本串,标签 1 后面必须跟数字,工具会对这两类做格式检查和转换,对不上时保留原始结构。
想看另一种紧凑格式,用MessagePack 编解码;无 schema 解析接口数据用Protobuf 解码。
常见问题
CBOR 和 MessagePack 有什么区别?
两者都是紧凑的二进制序列化。CBOR 来自 IETF 的 RFC 8949,设计上更贴近「二进制的 JSON」,带标签系统、不定长编码和半精度浮点;MessagePack 更早、库更多,但没有标准的标签机制。物联网和 COSE 生态用 CBOR 多,RPC 和缓存场景 MessagePack 更常见。
不定长编码是什么样?
数组、map、字节串和文本串都可以先写一个「不定长」的头部,然后依次放分块,最后用一个 0xff 的 break 字节收尾。这样流式写入时不必先知道总长度。工具会把分块拼好再展示,并在提示里说明遇到过分块。
标签(tag)会怎么显示?
常见标签会直接转成可读值:0 是日期时间字符串,1 是 Unix 时间戳,2 和 3 是大整数,21 和 22 是 Base64,32 是 URI,55799 是自描述标签。其它标签保留成 {"$tag":编号,"value":…},语义要靠对应的规范去查。
为什么某些数字变成了字符串?
超出 2^53-1 的整数在 JavaScript 的 number 里没法精确表示,工具用字符串保留原值,避免悄悄丢精度。大整数标签 2 和 3 也会转成十进制字符串,因为它们本来就是任意精度的。
半精度浮点是什么?
16 位浮点,指数 5 位、尾数 10 位,范围和精度都比 float32 小,但省一半空间,常用于传感器读数和机器学习模型。解码时会展开成普通的 number,看起来和 float32 的结果没有区别。
编码时 JSON 里的二进制怎么表示?
用 {"$bytes":"0a0b"},值是一段十六进制。反过来解码时遇到 major type 2(字节串)也会输出成这个形式,来回转换不会丢字节。普通字符串走 major type 3,两者在 CBOR 里是不同类型,不会混。