Protobuf:一种轻量级、高效的数据交换格式,附Java与Python数据交换示例

Protobuf(Protocol Buffers)是由 Google 开发的一种轻量级、高效的数据交换格式

本文仅做一个简单的代码演示,并不涉及原理说明

本文演示如何将Java数据通过文件的方式传递给Python
在这里插入图片描述

项目结构

protobuf-demo/
  protobuf-data        # 定义通用的数据结构
  protobuf-java        # Java项目序列化protobuf
  protobuf-python      # Python项目反序列化protobuf

下载安装Protobuf

# 检查系统版本
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.4
BuildVersion:   18E2035

# 下载解压 protoc-23.0-osx-x86_64.zip

$ ./bin/protoc --version
libprotoc 23.0

定义数据格式

protobuf-data/addressbook.proto

// 文件:addressbook.proto

// 指定 Protobuf 版本为版本3
syntax = "proto3";
// 指定 protobuf 包名,防止有相同类名的 message 定义
package com.example.protobuf;
// 是否生成多个文件
option java_multiple_files = true;
// 生成的文件存放在哪个包下
option java_package = "com.example.protobuf";
// 生成的类名,如果没有指定,会根据文件名自动转驼峰来命名
option java_outer_classname = "AddressBookProtos";

message Person {
    
    
  // =1,=2 作为序列化后的二进制编码中的字段的唯一标签,也因此,1-15 比 16 会少一个字节,所以尽量使用 1-15 来指定常用字段。
  optional int32 id = 1;
  optional string name = 2;
  optional string email = 3;

  enum PhoneType {
    
    
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    
    
    optional string number = 1;
    optional PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
    
    
  repeated Person people = 1;
}

使用 Protobuf 提供的编译器,可以将 .proto 文件编译成各种语言的代码文件(如 Java、C++、Python 等)。
在这里插入图片描述

Java代码序列化

依赖

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.22.3</version>
</dependency>

生成java代码

./bin/protoc --java_out=../protobuf-java/src/main/java ./addressbook.proto

项目结构

$ tree
.
├── pom.xml
├── protobuf-java.iml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── example
    │               └── protos
    │                   ├── AddressBook.java
    │                   ├── AddressBookOrBuilder.java
    │                   ├── AddressBookProtos.java
    │                   ├── Person.java
    │                   └── PersonOrBuilder.java
    └── test
        └── java
            └── com
                └── example

构建测试

package com.example;

import com.example.protos.AddressBook;
import com.example.protos.Person;
import org.junit.Test;

public class ProtobufTest {
    
    
    @Test
    public void testBuildProtobuf(){
    
    
        //  构建
        AddressBook addressBook = AddressBook
                .newBuilder()
                .addPeople(Person.newBuilder()
                        .setId(2)
                        .setName("小明")
                        .setEmail("[email protected]")
                        .addPhones(Person.PhoneNumber.newBuilder()
                                .setNumber("18388888888")
                                .setType(Person.PhoneType.HOME)
                        )
                )
                .build();
        System.out.println(addressBook);
    }
}

输出

people {
  id: 2
  name: "\345\260\217\346\230\216"
  email: "[email protected]"
  phones {
    number: "18388888888"
    type: HOME
  }
}

序列化

// 序列化成字节数组
byte[] byteArray = addressBook.toByteArray();
// 反序列化 - 字节数组转对象
AddressBook addressBook2 = AddressBook.parseFrom(byteArray);
System.out.println("字节数组反序列化:");
System.out.println(addressBook2);
// 序列化到文件
addressBook.writeTo(new FileOutputStream("AddressBook.txt"));
// 读取文件反序列化
AddressBook addressBook3 = AddressBook.parseFrom(new FileInputStream("AddressBook.txt"));
System.out.println("文件读取反序列化:");
System.out.println(addressBook3);

AddressBook.txt


)小明[email protected]"
18388888888

Python反序列化

安装依赖

pip install protobuf

生成Python代码

./bin/protoc --python_out=../protobuf-python ./addressbook.proto

目录

$ tree -I venv
.
├── AddressBook.txt            # 由上一步java代码输出的数据文件
├── addressbook_pb2.py         # 自动生成的文件
└── demo.py

反序列化示例 demo.py

# -*- coding: utf-8 -*-
"""
@File    : demo.py
@Date    : 2023-05-12
"""
import addressbook_pb2

if __name__ == '__main__':
    # 反序列化
    with open('AddressBook.txt', 'rb') as f:
        addressBook = addressbook_pb2.AddressBook()
        addressBook.ParseFromString(f.read())


        for person in addressBook.people:
            print(person.name)
            # 小明

直接打印addressBook对象

people {
  id: 2
  name: "\345\260\217\346\230\216"
  email: "[email protected]"
  phones {
    number: "18388888888"
    type: HOME
  }
}

Python的体验不是很好,代码提示的能力基本为零,需要使用dir(obj)查看对象属性才知道

完整代码:https://github.com/mouday/protobuf-demo

参考
Protobuf: 高效数据传输的秘密武器
Python使用protobuf序列化和反序列化

猜你喜欢

转载自blog.csdn.net/mouday/article/details/130639021