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

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

目录

下载安装Protobuf

定义数据格式

Java代码序列化

Python反序列化

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


官方文档:https://protobuf.dev/overview/

GitHub:https://github.com/protocolbuffers/protobuf

https://github.com/protocolbuffers/protobuf/releases/latest

VSCode语法高亮插件:vscode-proto

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


本文演示如何将Java数据通过文件的方式传递给Python


9682c201b800da6799bd08792964858f_eb7966630daf4613bc3e19d9fb7b8602.png

项目结构


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 等)。


572bf2f9c894b44ad13db87b195fea06_1760c47412b84ac2988e33595c3aaa3d.png

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

1

项目结构


$ 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("yyds@126.com")

                       .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: "yyds@126.com"

 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



)小明yyds@126.com"

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: "yyds@126.com"

 phones {

   number: "18388888888"

   type: HOME

 }

}



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


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


参考

Protobuf: 高效数据传输的秘密武器

Python使用protobuf序列化和反序列化

————————————————

版权声明:本文为CSDN博主「彭世瑜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/mouday/article/details/130639021

相关文章
|
1月前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
59 1
|
14天前
|
前端开发 JavaScript Java
java常用数据判空、比较和类型转换
本文介绍了Java开发中常见的数据处理技巧,包括数据判空、数据比较和类型转换。详细讲解了字符串、Integer、对象、List、Map、Set及数组的判空方法,推荐使用工具类如StringUtils、Objects等。同时,讨论了基本数据类型与引用数据类型的比较方法,以及自动类型转换和强制类型转换的规则。最后,提供了数值类型与字符串互相转换的具体示例。
|
25天前
|
人工智能 安全 Java
Java和Python在企业中的应用情况
Java和Python在企业中的应用情况
48 7
|
21天前
|
JSON Java 程序员
Java|如何用一个统一结构接收成员名称不固定的数据
本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。
24 3
|
25天前
|
Java 程序员 开发工具
在比较Java和Python哪个更易学
在比较Java和Python哪个更易学
34 4
|
26天前
|
机器学习/深度学习 人工智能 自然语言处理
比较Python和Java哪个更好
比较Python和Java哪个更好
39 5
|
25天前
|
Java 程序员 Python
Java和Python
Java和Python
24 2
|
26天前
|
Java
在Java中实现接口的具体代码示例
可以根据具体的需求,创建更多的类来实现这个接口,以满足不同形状的计算需求。希望这个示例对你理解在 Java 中如何实现接口有所帮助。
41 1
|
1月前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
1月前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
70 2