json和pb文件的互换及文件压缩

Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

在数据传输过程中,基于性能我们通常需要将json文件转为pb文件传输。本文就主要介绍json和pb文件相互转换的流程。

安装protobuf

1. 安装protobuf

下载源码 https://github.com/protocolbuffers/protobuf/releases

下载压缩包后进行解压和安装

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类。

protoc  --python_out=. test.proto  

能够生成test_pb2.py文件。

为了方便转换,我们使用简单的json文件格式做实验~

json文件:

{
"class1":{
"key1":3.14,
"key2":"test",
"key3":[1,2,3,4]
}
}

test.proto:

syntax = "proto3";

message TestMessage {

    message Class1 {
        double key1 = 1;
        string key2 = 2;
        repeated uint32 key3 = 3;
    }

    Class1 class1 = 1;
}

生成test_pb2.py

# -*- 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文件进行相互转换了。

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)

得到输出

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:

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:

lz4 test.pb

gzip

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

原文地址:https://cloud.tencent.com/developer/article/2182255

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340