在嵌入式行业,有大量的工程师在使用header type value crc这种十六进制的编码协议。
这种协议的好处是数据紧凑,数据量小。 坏处是可读性差,维护困难。
也有很多嵌入式工程师开始使用cjson,好处不需要多讲。 坏处是json序列化之后的数据长度,是十六进制t l v格式的3~4倍。
常用的数据编码有以下:
xml: 带位置关系的文本格式 适合网页渲染
json: 3.5倍长度 适用于app 与 服务器之间、服务器与服务器之间通讯
cbor: 2倍长度 既具备json的可读性,又具备二进制的紧凑性。区块链里面有用这种数据编码,例如filecoin
protobuf: 1.2倍长度 适用于网络游戏,坏处是强耦合性(app和服务器需要随时保持同步,同过.proto文件存储位置元数据)
xml 是通过tag标签匹配。
json解析时是通过特殊符号," ’ { } [] 的匹配,来确定key:value,是位置无关编码,可读性最强,但是特殊符合过多。
cbor是通过传入是头、数据类型、key,没有特殊字符。
protobuf是把位置数据写入文件字符串,编解码时按照字符串文件来序列化/反序列化到变量。
下面以cbor为例子,实测与json、hex编码后数据压缩比例。
python demo代码:
import cbor2
import json
import re# 原始数据
data = {'tag': 'gps','name': 'king','age': 99999,'addr': '上海','lon': 23.12335555,'lat': 118.15155615,'timestamp': 32158520,'lang': ['Python', '爬虫', 'Golang', 'ssh', 'impl']
}# JSON编码
json_data = json.dumps(data, ensure_ascii=False)
json_bytes = json_data.encode('utf-8')# CBOR编码
cbor_bytes = cbor2.dumps(data)# 提取JSON值部分并拼接为字节(修复版)
def extract_json_values(json_str):"""仅提取JSON字符串中的值部分(不包括键名)"""# 匹配键值对的正则表达式key_value_pattern = re.compile(r'"([^"]+)":\s*("[^"]*"|\d+\.?\d*|true|false|null)')# 匹配数组的正则表达式array_pattern = re.compile(r'\[([^\]]*)\]')# 匹配数组元素的正则表达式array_item_pattern = re.compile(r'"([^"]*)"|\d+\.?\d*|true|false|null')byte_parts = []# 处理键值对for match in key_value_pattern.finditer(json_str):value = match.group(2)if value.startswith('"') and value.endswith('"'):# 字符串值byte_parts.append(value[1:-1].encode('utf-8'))else:# 数字、布尔值、nullbyte_parts.append(value.encode('utf-8'))# 处理数组for array_match in array_pattern.finditer(json_str):array_content = array_match.group(1)for item_match in array_item_pattern.finditer(array_content):item = item_match.group(0)if item.startswith('"') and item.endswith('"'):byte_parts.append(item[1:-1].encode('utf-8'))else:byte_parts.append(item.encode('utf-8'))return b''.join(byte_parts)# 提取纯JSON值(不包括键名)
json_values_bytes = extract_json_values(json_data)# 格式化十六进制输出(带地址偏移)
def format_hex(bytes_data, bytes_per_line=16, group_size=2):hex_str = bytes_data.hex(' ')formatted = []for i in range(0, len(hex_str), bytes_per_line * (group_size + 1)):line = hex_str[i:i + bytes_per_line * (group_size + 1)]addr = f"{i//(group_size + 1):08x}"formatted.append(f"{addr}: {line}")return "\n".join(formatted)# 对比JSON值HEX与CBOR HEX(修复版)
def compare_hex(json_hex, cbor_hex, max_compare=100):def extract_pure_hex(hex_str):return re.sub(r'^.*?: | ', '', hex_str, flags=re.MULTILINE).replace(' ', '')json_pure_hex = extract_pure_hex(json_hex)cbor_pure_hex = extract_pure_hex(cbor_hex)max_length = min(len(json_pure_hex) // 2, len(cbor_pure_hex) // 2, max_compare)json_bytes = bytes.fromhex(json_pure_hex[:max_length*2])cbor_bytes = bytes.fromhex(cbor_pure_hex[:max_length*2])result = []result.append("| 位置 | JSON值HEX | CBOR HEX | 对比结果 |")result.append("|" + "-" * 76 + "|")for i in range(max_length):jb = json_bytes[i] if i < len(json_bytes) else Nonecb = cbor_bytes[i] if i < len(cbor_bytes) else Nonejb_hex = f"0x{jb:02x}" if jb is not None else " "cb_hex = f"0x{cb:02x}" if cb is not None else " "remark = "相同字节" if jb == cb and jb is not None else "不同字节" if jb is not None and cb is not None else "JSON值结束" if jb is None else "CBOR结束"result.append(f"| {i:4d} | {jb_hex:18} | {cb_hex:18} | {remark:20} |")return "\n".join(result)# 输出结果
print("原始数据:\n", data)
print("\n--- JSON编码 ---")
print(f"JSON字符串: {json_data}")
print(f"JSON字节长度: {len(json_bytes)} 字节")
print("JSON十六进制:\n", format_hex(json_bytes))
print("\n--- CBOR编码 ---")
print(f"CBOR字节长度: {len(cbor_bytes)} 字节")
print("CBOR十六进制:\n", format_hex(cbor_bytes))
print("\n--- JSON值字节拼接后的HEX ---")
print(f"JSON值hex长度: {len(json_values_bytes)} 字节")
print("JSON值拼接HEX:\n", format_hex(json_values_bytes))
print(f'len(json) / len(hex) = {len(json_bytes) / len(json_values_bytes)}倍')
print(f'len(json) / len(cbor) = {len(json_bytes) / len(cbor_bytes)}倍')
print(f'len(cbor) / len(hex) = {len(cbor_bytes) / len(json_values_bytes)}倍')
实测:
root@iZwz99zhkxxl5h6ecbm2xwZ:~# python3 cbor.py
原始数据:{'tag': 'gps', 'name': 'king', 'age': 99999, 'addr': '上海', 'lon': 23.12335555, 'lat': 118.15155615, 'timestamp': 32158520, 'lang': ['Python', '爬虫', 'Golang', 'ssh', 'impl']}--- JSON编码 ---
JSON字符串: {"tag": "gps", "name": "king", "age": 99999, "addr": "上海", "lon": 23.12335555, "lat": 118.15155615, "timestamp": 32158520, "lang": ["Python", "爬虫", "Golang", "ssh", "impl"]}
JSON字节长度: 181 字节
JSON十六进制:00000000: 7b 22 74 61 67 22 3a 20 22 67 70 73 22 2c 20 22
00000010: 6e 61 6d 65 22 3a 20 22 6b 69 6e 67 22 2c 20 22
00000020: 61 67 65 22 3a 20 39 39 39 39 39 2c 20 22 61 64
00000030: 64 72 22 3a 20 22 e4 b8 8a e6 b5 b7 22 2c 20 22
00000040: 6c 6f 6e 22 3a 20 32 33 2e 31 32 33 33 35 35 35
00000050: 35 2c 20 22 6c 61 74 22 3a 20 31 31 38 2e 31 35
00000060: 31 35 35 36 31 35 2c 20 22 74 69 6d 65 73 74 61
00000070: 6d 70 22 3a 20 33 32 31 35 38 35 32 30 2c 20 22
00000080: 6c 61 6e 67 22 3a 20 5b 22 50 79 74 68 6f 6e 22
00000090: 2c 20 22 e7 88 ac e8 99 ab 22 2c 20 22 47 6f 6c
000000a0: 61 6e 67 22 2c 20 22 73 73 68 22 2c 20 22 69 6d
000000b0: 70 6c 22 5d 7d--- CBOR编码 ---
CBOR字节长度: 117 字节
CBOR十六进制:00000000: a8 63 74 61 67 63 67 70 73 64 6e 61 6d 65 64 6b
00000010: 69 6e 67 63 61 67 65 1a 00 01 86 9f 64 61 64 64
00000020: 72 66 e4 b8 8a e6 b5 b7 63 6c 6f 6e fb 40 37 1f
00000030: 94 3a b5 07 b4 63 6c 61 74 fb 40 5d 89 b3 18 90
00000040: f0 7e 69 74 69 6d 65 73 74 61 6d 70 1a 01 ea b3
00000050: 38 64 6c 61 6e 67 85 66 50 79 74 68 6f 6e 66 e7
00000060: 88 ac e8 99 ab 66 47 6f 6c 61 6e 67 63 73 73 68
00000070: 64 69 6d 70 6c--- JSON值字节拼接后的HEX ---
JSON值hex长度: 74 字节
JSON值拼接HEX:00000000: 67 70 73 6b 69 6e 67 39 39 39 39 39 e4 b8 8a e6
00000010: b5 b7 32 33 2e 31 32 33 33 35 35 35 35 31 31 38
00000020: 2e 31 35 31 35 35 36 31 35 33 32 31 35 38 35 32
00000030: 30 50 79 74 68 6f 6e e7 88 ac e8 99 ab 47 6f 6c
00000040: 61 6e 67 73 73 68 69 6d 70 6c
len(json) / len(hex) = 2.445945945945946倍
len(json) / len(cbor) = 1.547008547008547倍
len(cbor) / len(hex) = 1.5810810810810811倍
root@iZwz99zhkxxl5h6ecbm2xwZ:~#