## 一、概述
类似 Json或 xml,ProtoBuf是一种数据交换协议;跟json和xml这类相比,其在效率、兼容性等方面非常出色;
### **特点:**
* **语言无关、平台无关**。即 ProtoBuf 支持 Java、C++、Python 等多种语言,支持多个平台;
* **高效**。即比 xml更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单;
* **扩展性、兼容性好**。你可以更新数据结构,而不影响和破坏原有的旧程序;
### **比较**
* xml、Json、ProtoBuf 都具有**数据结构化**和**数据序列化**的能力
* xml、Json更注重**数据结构化**,关注人类可读性和语义表达能力。ProtoBuf 更注重**数据序列化**,关注效率、空间、速度,人类可读性差,语义表达能力不足(为保证极致的效率,会舍弃一部分元信息)
* ProtoBuf 的应用场景更为明确,xml、Json的应用场景更为丰富。
## 二、使用
**第一步,创建 .proto 文件,定义数据结构,如下所示**
~~~protobuf
syntax = "proto3";
option java_package = "com.ray.test.protos";
option java_outer_classname = "RayProtoModel";
message Model {
int64 id = 1;
string action = 2;
string content = 3;
string sender = 4;
string receiver = 5;
string extra = 6;
string title = 7;
string format = 8;
int64 timestamp = 9;
}
~~~
字段定义规则:
~~~protobuf
message xxx {
// 字段规则:required -> 字段只能也必须出现 1 次
// 字段规则:optional -> 字段可出现 0 次或1次
// 字段规则:repeated -> 字段可出现任意多次(包括 0)
// 类型:int32、int64、sint32、sint64、string、32-bit ....
// 字段编号:0 ~ 536870911(除去 19000 到 19999 之间的数字)
字段规则 类型 名称 = 字段编号;
}
~~~
**第二步,protoc 编译 .proto 文件生成读写接口**
我们在 .proto 文件中定义了数据结构,这些数据结构是面向开发者和业务程序的,并不面向存储和传输;
当需要把这些数据进行存储或传输时,就需要将这些结构数据进行序列化、反序列化以及读写。那么如何实现呢?不用担心, ProtoBuf 将会为我们提供相应的接口代码。如何提供?答案就是通过 protoc 这个编译器;
### **下载安装**
下载编译器:[Releases · protocolbuffers/protobuf (github.com)](https://github.com/protocolbuffers/protobuf/releases),取最新版本,找到类似如下包下载:
![](https://img.kancloud.cn/27/52/2752b31121ae71c3931bdd3e3c92c830_1366x657.png)
解压文件包:
![](https://img.kancloud.cn/ea/fb/eafb314bd739d4424be1e7bea88632b1_948x301.png)
bin目录中,包含了protoc编译器;
![](https://img.kancloud.cn/69/e4/69e4438e2e5421161ec3bc7fe794e2bd_913x295.png)
### **生成代码**
可通过如下命令生成相应的接口代码,以java为例:
~~~
protoc.exe -I=${protofilepath}--java_out=${javaout} ${protofilepathwithfilename}
~~~
![](https://img.kancloud.cn/98/91/98915ed4aaba409674af2bd35282339e_677x457.png)
生成的代码:
![](https://img.kancloud.cn/8e/07/8e07056268156a94f6901e7544c14129_1086x429.png)
**第三步,调用接口实现序列化、反序列化以及读写**
```
public class ProtoBufUtil
{
public static void main(String[] args) throws IOException
{
RayProtoModel.Model.Builder builder = RayProtoModel.Model.newBuilder();
builder.setId(1);
builder.setAction("2");
builder.setExtra("3");
RayProtoModel.Model model = builder.build();
System.out.println(model.toString());
// 模拟将对象转成byte[],方便传输
for (byte b : model.toByteArray())
{
System.out.print(b);
}
System.out.println(model.toByteString());
// 模拟接收Byte[],反序列化成Model类
byte[] byteArray = model.toByteArray();
RayProtoModel.Model p2 = RayProtoModel.Model.parseFrom(byteArray);
System.out.println("after :" + p2.toString());
}
}
```