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() 方法。
// 初始化方法1
Person 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();
// 初始化方法2
Person.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转jsonString
String 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/