## 一、概述
類似 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),取最新版本,找到類似如下包下載:

解壓文件包:

bin目錄中,包含了protoc編譯器;

### **生成代碼**
可通過如下命令生成相應的接口代碼,以java為例:
~~~
protoc.exe -I=${protofilepath}--java_out=${javaout} ${protofilepathwithfilename}
~~~

生成的代碼:

**第三步,調用接口實現序列化、反序列化以及讀寫**
```
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());
}
}
```