Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
在数据传输过程中,基于性能我们通常需要将json文件转为pb文件传输。本文就主要介绍json和pb文件相互转换的流程。
安装protobuf
1. 安装protobuf
下载源码 https://github.com/protocolbuffers/protobuf/releases
下载压缩包后进行解压和安装
代码语言:javascript复制tar -zxvf protobug-all-3.19.0.tar.gz
cd protobuf-3.19.0 && ./configure && make && make check && sudo make install
安装成功后可以通过protoc --version校验是否安装成功。
2. python安装protobuf
pip3 install protobuf
安装完成之后能成功导入 google.protobuf表示成功。
import google.protobuf
编写proto文件
json和pb文件转换,首先需要有一个proto文件,主要定义需要处理的数据的结构,也就是
定义你要的消息和消息中的各个字段及其数据类型。
我们需要对着要处理的json文件的格式来编写proto,纯手写proto文件是个费时和麻烦的事情,有些工具可以提高我们写proto的效率
https://json-to-proto.github.io/
简单举例
如果json文件相对复杂或者格式不规范,可能会引起后续转换时的问题,可以根据提示调整生成的proto文件,我主要遇到的问题是array of dissimliar objects问题, 需要修改json文件格式。
如果使用其他的在线转换工具,可能会遇到:没有加分号,索引不是从1开始,添加了required关键字等问题。
使用python对json和pb转换
根据以上工具,我们已经有了一个proto文件test.proto,下面我们利用protoc生成一个python类。
代码语言:javascript复制protoc --python_out=. test.proto
能够生成test_pb2.py文件。
为了方便转换,我们使用简单的json文件格式做实验~
json文件:
代码语言:javascript复制{
"class1":{
"key1":3.14,
"key2":"test",
"key3":[1,2,3,4]
}
}
test.proto:
代码语言:javascript复制syntax = "proto3";
message TestMessage {
message Class1 {
double key1 = 1;
string key2 = 2;
repeated uint32 key3 = 3;
}
Class1 class1 = 1;
}
生成test_pb2.py
代码语言:javascript复制# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: test.proto
"""Generated protocol buffer code."""
...
...
DESCRIPTOR = _descriptor.FileDescriptor(
name='test.proto',
package='',
syntax='proto3',
serialized_options=None,
create_key=_descriptor._internal_create_key,
...
...
TestMessage = _reflection.GeneratedProtocolMessageType('TestMessage', (_message.Message,), {
...
...
# @@protoc_insertion_point(module_scope)
接下来我们就可以对json和pb文件进行相互转换了。
代码语言:javascript复制from example.test_pb2 import TestMessage
from google.protobuf import json_format
import json
msg = TestMessage()
def pb_to_json(pb_str):
"""将pbstring转化为jsonString"""
json_str=json_format.MessageToJson(pb_str)
return json_str
def json_to_pb(json_str):
"""将jsonString转化为pbString"""
pb_str = json_format.Parse(json.dumps(json_str), msg)
return pb_str
if __name__ == '__main__':
json_obj={"class1":{"key1":3.14,"key2":"test","key3":[1,2,3,4]}}
pb_str=json_to_pb(json_obj)
print("json_to_pb request---n",pb_str)
print(type(pb_str))
with open('test.pb', 'wb') as fb:
# 写.pb文件
print("json_to_pb write---n",type(pb_str.SerializeToString()))
fb.write(pb_str.SerializeToString())
json_str = pb_to_json(pb_str)
print("pb_to_json request---n",json_str)
print(type(json_str))
with open('test.json', 'w') as fb:
# 写json文件
fb.write(json_str)
得到输出
代码语言:javascript复制json_to_pb request---
class1 {
key1: 3.14
key2: "test"
key3: 1
key3: 2
key3: 3
key3: 4
}
<class 'test_pb2.TestMessage'>
json_to_pb write---
<class 'bytes'>
pb_to_json request---
{
"class1": {
"key1": 3.14,
"key2": "test",
"key3": [
1,
2,
3,
4
]
}
}
<class 'str'>
我们再看看生成的文件大小
可以看出pb文件只占json文件的20%。
对pb文件的进一步压缩
如果想进一步压缩pb,我们还可以使用一些压缩工具
zlib:
代码语言:javascript复制def compress_zlib(infile, dst, level=9):
infile = open(infile, 'rb')
dst = open(dst, 'wb')
compress = zlib.compressobj(level)
data = infile.read(1024)
while data:
dst.write(compress.compress(data))
data = infile.read(1024)
dst.write(compress.flush())
lz4:
代码语言:javascript复制lz4 test.pb
gzip
代码语言:javascript复制gzip frame_d2f.pb
当然压缩率要根据实际数据,我只是介绍这些工具的使用。
从压缩文件大小来看,本文简单实例就不适合使用这些压缩工具。
参考:
https://blog.csdn.net/u013421629/article/details/114022392
https://www.cnblogs.com/smileyes/p/9797258.html
https://github.com/protocolbuffers/protobuf/releases
https://blog.csdn.net/DinnerHowe/article/details/79805250
https://www.cnblogs.com/xueweihan/p/10167924.html