Java读取及生成pb文件并转换jsonString
- 1. 效果图
- 2. 原理
- 2.1 Protocol Buffers是什么
- 2.2 支持的语言
- 2.3 根据.proto生成.java
- 2.4 初始化及构建pb,读取,转jsonString
- 3. 源码
- 3.1 address.proto
- 3.2 PbParseUtil.java
- 参考
- 读取pb及生成pb文件
- pb文件转换jsonString
- 二进制pb转换jsonString
- 赋值(有空或者类型不对应会无法赋值及报错)
1. 效果图
2. 原理
2.1 Protocol Buffers是什么
协议缓冲区是用于序列化结构化数据的与语言无关、与平台无关的可扩展机制。
协议缓冲区(Protocol Buffers又名protobuf)是 Google 的语言中立、平台中立、可扩展的 序列化结构化数据的机制 – 想想 XML,但更小、更快、 简单。只需定义一次数据的结构,然后就可以 使用特殊生成的源代码轻松编写和读取结构化数据,往返各种数据流并使用多种语言。
2.2 支持的语言
协议缓冲区目前支持Java,Python,Objective-C,中生成的代码 和C++。使用新的 proto3 语言版本,还可以使用 Kotlin, Dart,Go,Ruby,PHP和C#,还有更多的语言即将推出。
2.3 根据.proto生成.java
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
2.4 初始化及构建pb,读取,转jsonString
标准消息方法:
- isInitialized():检查是否已设置所有必填字段。
- toString():返回消息的人类可读表示形式, 对于调试特别有用。
- mergeFrom(Message other):(仅限构建器)合并 的内容 other 到此消息中,覆盖奇异标量字段,合并复合 字段,并连接重复字段。
- clear():(仅限构建器)将所有字段清除回空状态。
解析和序列化:
- byte[] toByteArray();:序列化消息并返回一个字节数组 包含其原始字节。
- static Person parseFrom(byte[] data);:解析来自给定的消息 字节数组。
- void writeTo(OutputStream output);:序列化消息并写入它 到一个 OutputStream.
- static Person parseFrom(InputStream input);:读取和分析消息 从 InputStream.
3. 源码
3.1 address.proto
syntax = "proto3";package tutorial;option java_multiple_files = true;
option java_package = "com.example.tutorial.protos";
option java_outer_classname = "AddressBookProtos";message Person {string name = 1;int32 id = 2;string email = 3;Geometry geometry=4;repeated PhoneNumber phones = 5;enum PhoneType {PHONE_TYPE_UNSPECIFIED = 0;PHONE_TYPE_MOBILE = 1;PHONE_TYPE_HOME = 2;PHONE_TYPE_WORK = 3;}message PhoneNumber {string number = 1;PhoneType type = 2;}message Geometry {repeated Point point=1;}message Point{double longitude = 1;double latitude = 2;double altitude = 3;}}message AddressBook {repeated Person people = 1;
}
3.2 PbParseUtil.java
package com.test.utils;import com.example.tutorial.protos.AddressBook;
import com.example.tutorial.protos.Person;
import com.googlecode.protobuf.format.JsonFormat;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/**************************************Class Name: PbParseUtil*Description: <pb读取转换工具类>*@author: Seminar*@create: 2023/7/31*@since 1.0.0*************************************/
public class PbParseUtil {// 打印pb的所有字段static void Print(AddressBook addressBook) {for (Person person : addressBook.getPeopleList()) {System.out.println("Person ID: " + person.getId());System.out.println(" Name: " + person.getName());if (StringUtils.isNotEmpty(person.getEmail())) {System.out.println(" E-mail address: " + person.getEmail());}for (Person.PhoneNumber phoneNumber : person.getPhonesList()) {switch (phoneNumber.getType()) {case PHONE_TYPE_MOBILE:System.out.print(" Mobile phone #: ");break;case PHONE_TYPE_HOME:System.out.print(" Home phone #: ");break;case PHONE_TYPE_WORK:System.out.print(" Work phone #: ");break;}System.out.println(phoneNumber.getNumber());}if (person.getGeometry() != null) {for (Person.Point point : person.getGeometry().getPointList()) {System.out.println("lon: " + point.getLongitude() + ",lat: " + point.getLatitude() + ",alt: " + point.getAltitude());}}}}public static void main(String[] args) throws IOException {// 协议缓冲区编译器生成的消息类都是 不可变 。消息对象一旦构造完成,就无法修改,// 要构造消息,必须首先构造一个 生成器,将要设置的任何字段设置为所选值,然后调用build() 方法。// 初始化方法1Person john = Person.newBuilder().setId(1234).setName("John Doe").setEmail("jdoe@example.com").addPhones(Person.PhoneNumber.newBuilder().setNumber("555-4321").setType(Person.PhoneType.PHONE_TYPE_HOME)).build();// 初始化方法2Person.Builder person = Person.newBuilder();person.setEmail("1222@qq.com");person.setName("Lucy");person.setId(1).addPhones(Person.PhoneNumber.newBuilder().setNumber("12634524230").setType(Person.PhoneType.PHONE_TYPE_MOBILE));// java pb转二进制byte[] personPb = john.toByteArray();// java pb转pb文件byte[] personPb2 = person.build().toByteArray();String pbFilePath = System.getProperty("user.dir") + File.separator + "person.pb";try (FileOutputStream fileWriter = new FileOutputStream(pbFilePath)) {fileWriter.write(personPb2);}// pb二进制转Java对象// pb文件转Java对象Person person1 = Person.parseFrom(personPb);Person person2 = Person.parseFrom(new FileInputStream(pbFilePath));// pb文件转Java对象Person.Builder person3 = Person.newBuilder();person3.mergeFrom(new FileInputStream(pbFilePath));// 某些字段没有的,需要单独设置Person.Geometry.Builder geometryBuilder = Person.Geometry.newBuilder();for (int i = 0; i < 3; i++) {geometryBuilder.addPoint(Person.Point.newBuilder().setLongitude(113.222222 + i * 1.5).setLatitude(40.1 + i * 0.89).setAltitude(40 + i * 0.45).build());}person3.setGeometry(geometryBuilder.build());System.out.println("person1 name: " + person1.getName());System.out.println("person2 name: " + person2.getName());System.out.println("person3 name: " + person2.getName());AddressBook address = AddressBook.newBuilder().addPeople(person1).addPeople(person3).build();Print(address);// pb转jsonStringString str = JsonFormat.printToString(address);System.out.println("jsonStr: " + str);}
}
参考
- http://code.google.com/p/protobuf/
- Java proto 如何生成和反序列化消息
- pb文件读取:https://blog.csdn.net/feiying0canglang/article/details/126125854
- pb文件转java对象:https://protobuf.dev/getting-started/javatutorial/