protobuf
(protocol buffer) 是谷歌内部的混合语言数据标准。通过将结构化的数据进行序列化(串行化),用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。通常说的protobuf包括以下三点:
- 是一种二进制数据交换格式。支持不同与语言例如C++、java中定义的存储类的内容与二进制序列串相互转换,主要用于数据传输或保存。
- 定义了一种源文件,扩展名为.proto.使用此文件,可以定义存储类的内容。
- 可以使用编译器将.proto编译成.cc 或.java,使之成为一个可以在C++或java等工程中直接使用的类。
定义Proto文件
message
:protobuf
中定义一个消息类型是通过关键字message
字段指定的,这个关键字类似于C++/Java中的class关键字。使用protobuf编译器将proto
编译成C++代码之后,每个message
都会生成一个名字与之对应的C++类,该类公开继承自google::protobuf::Message
创建turorial.person.proto 文件,文件内容如下:
// FileName: tutorial.person.proto // 通常文件名建议命名格式为 包名.消息名.proto // 表示正在使用proto2命令 syntax = "proto2"; //包声明,tutorial 也可以声明为二级类型。 //例如a.b,表示a类别下b子类别 package tutorial; //编译器将生成一个名为person的类 //类的字段信息包括姓名name,编号id,邮箱email, //以及电话号码phones message Person { required string name = 1; // (位置1) required int32 id = 2; optional string email = 3; // (位置2) enum PhoneType { //电话类型枚举值 MOBILE = 0; //手机号 HOME = 1; //家庭联系电话 WORK = 2; //工作联系电话 } 文章来源地址https://www.toymoban.com/news/detail-587235.html //电话号码phone消息体 //组成包括号码number、电话类型 type message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; // (位置3) }
repeated PhoneNumber phones = 4; // (位置4) }文章来源:https://www.toymoban.com/news/detail-587235.html // 通讯录消息体,包括一个Person类的people message AddressBook { repeated Person people = 1; } |
字段解释:
包声明
proto
文件以package
声明开头,这有助于防止不同项目之间命名冲突。在C++中,以package
声明的文件内容生成的类将放在与包名匹配的namespace
中,上面的.proto
文件中所有的声明都属于tutorial
。
标识符:
protobuf协议的标识符为message或enum,如示例中的Person和PhoneType。message标识一条消息,enum标识一个枚举类型。使用protobuf编译器将协议文件编译后,message和enum都会生成一个类
字段规则
· repeated: 消息体中可重复字段,重复的值的顺序会被保留(例如位置3)。其中,proto3默认使用packed方式存储,这样编码方式比较节省内存。
标识号
标识号
:在消息体的定义中,每个字段都必须要有一个唯一的标识号,标识号是[0,2^29-1]范围内的一个整数。以Person为例,name=1,id=2, email=3, phones=4 中的1-4就是标识号。
数据定义
许多标准的简单数据类型都可以用作message
字段类型,包括bool
,int32
,float
,double
和string
。还可以使用其他message
类型作为字段类型在消息体中添加更多结构。在上面的示例中,Person
包含PhoneNumber message
, 而AddressBook
包含Person message
。甚至可以定义嵌套在其他message中的message类型。例如,上面的PhoneNumber
定义在Person
。
在java中使用protobuf的简单示例
以下是示例中用到的proto文件teacher.proto:
syntax = "proto3"; package space; message course{ // 课程名称 string name = 1; // 课程分数 int32 score = 2; } message student{ // 学生名称 string name = 1; // 学生年龄 int32 age = 2; // 学生所修课程,可能是多门,是一组数组 repeated course course = 3; } |
从Release Protocol Buffers v3.5.1 · protocolbuffers/protobuf · GitHub 下载protoc工具,此工具可以根据proto文件生成java类。
下载完成后,解压缩该文件。
打开cmd命令窗口,跳转至解压缩路径:
执行以下命令:
protoc.exe --java_out=src/main/java/ teacher.proto |
执行此命令前,需要在新建文件夹目录src/main/java
执行成功后,可以看到在src/main/java 下生成的java类文件Teacher.java。
新建一个maven工程,并导入以下pom依赖
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.21.9</version> </dependency> <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util --> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java-util</artifactId> <version>3.21.9</version> </dependency> <!-- https://mvnrepository.com/artifact/io.grpc/grpc-all --> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-all</artifactId> <version>1.11.0</version> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact> com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact> io.grpc:protoc-gen-grpc-java:1.11.0:exe:${os.detected.classifier} </pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> |
将Teacher.java 添加至该工程。新建一个测试类TestMyProtobuf.java 进行测试。代码如下:
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; import space.Teacher; import java.util.Arrays; public class TestMyProtobuf { public static void main(String[] args) { // 生成课程1对象 Teacher.course.Builder courseBuilder1 = Teacher.course.newBuilder(); courseBuilder1.setName("Java"); courseBuilder1.setScore(99); Teacher.course course1 = courseBuilder1.build(); // 生成课程2对象 Teacher.course.Builder courseBuilder2 = Teacher.course.newBuilder(); courseBuilder2.setName("Python"); courseBuilder2.setScore(98); Teacher.course course2 = courseBuilder2.build(); // 生成学生对象 Teacher.student.Builder studentBuilder = Teacher.student.newBuilder(); studentBuilder.setName("Lucy"); studentBuilder.setAge(23); studentBuilder.addCourse(0,course1); studentBuilder.addCourse(1,course2); Teacher.student student = studentBuilder.build(); // proto对象 System.out.println("The student object is: \n" + student); // 序列化 byte[] studentByte = student.toByteArray(); System.out.println("The student after encode is:\n" + Arrays.toString(studentByte)); try { // 反序列化 Teacher.student newStudent = Teacher.student.parseFrom(studentByte); System.out.println("The student after decode is:\n" + newStudent); // 转换json System.out.println("The student json format is:\n" + JsonFormat.printer().print(student)); } catch (InvalidProtocolBufferException e) { e.printStackTrace(); } } } |
测试结果如下:
The student object is: name: "Lucy" age: 23 course { name: "Java" score: 99 } course { name: "Python" score: 98 } The student after encode is: [10, 4, 76, 117, 99, 121, 16, 23, 26, 8, 10, 4, 74, 97, 118, 97, 16, 99, 26, 10, 10, 6, 80, 121, 116, 104, 111, 110, 16, 98] The student after decode is: name: "Lucy" age: 23 course { name: "Java" score: 99 } course { name: "Python" score: 98 } The student json format is: { "name": "Lucy", "age": 23, "course": [{ "name": "Java", "score": 99 }, { "name": "Python", "score": 98 }] }
|
到了这里,关于Protobuf 简介的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!