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

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...