一、基础理论
Protocol Buffers是语言无关,平台无关拓展机制,用于序列化结构数据。
ProtoBuf 解决的问题?
1.大小不超过几兆字节的类型化结构化数据数据包提供序列化格式
2.非常通用的数据结构用于文件存储格式和网络传输格式
开发者只需要定义.proto
文件就可以生成各种语言对应的代码,例如:
message Person {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
}
生成的Java代码
Person john = Person.newBuilder()
.setId(1234)
.setName("John Doe")
.setEmail("jdoe@example.com")
.build();
output = new FileOutputStream(args[0]);
john.writeTo(output);
ProtoBuf 的优点
1.紧凑的数据存储
2.快速解析
3.支出多种编程语言
4.通过自动生成的类优化功能
不适用 ProtoBuf 的场景
1.不适合处理较大的数据,超过几 MB 的数据
2.相同的数据可以具有许多不同的二进制序列化
3.消息不会压缩
4.涉及大型多维浮点数数组的许多科学和工程用途
二、代码示例
开发环境:
golang 1.20.1
protoc libprotoc 3.20.3
使用 Github create label的接口作为演示
Create Label 接口
代码目录结构
├── com
│ └── example
│ └──label
│ └──label.pb.go
├── go.mod
├── go.sum
├── label.proto
└── main.go
syntax = "proto3";
package label;
option go_package = "com/example/label";
message CreateLabelRequest{
string name = 1;
optional string color = 2;
optional string description = 3;
}
message CreateLabelResponse{
int64 id = 1;
string node_id = 2;
string url = 3;
string name = 4;
string description = 5;
string color = 6;
bool default = 7;
}
message ListLabelRequest{
string owner = 1;
string repo = 2;
int32 milestone_number = 3;
optional int32 per_page = 4;
optional int32 page = 5;
}
message ListLabelResponse{
int32 code = 1;
string message = 2;
repeated CreateLabelResponse items = 3;
}
使用命令生成对应的 golang 文件
protoc --go_out=. *.proto
测试代码
package main
import (
"example.com/com/example/label"
"log"
)
func main() {
label1 := label.CreateLabelRequest{
Name: "bug",
Color: nil,
Description: nil,
}
log.Print(label1.String())
color := "12345"
description := "hello"
label2 := label.CreateLabelRequest{
Name: "bug",
Color: &color,
Description: &description,
}
log.Print(label2.String())
labelResp := label.CreateLabelResponse{
Id: 208045946,
NodeId: "MDU6TGFiZWwyMDgwNDU5NDY=",
Url: "https://api.github.com/repos/octocat/Hello-World/labels/bug",
Name: "bug",
Description: "Something isn't working",
Color: "f29513",
Default: true,
}
log.Print(labelResp.String())
perPage := int32(30)
page := int32(1)
label3 := label.ListLabelRequest{
Owner: "zhang san",
Repo: "example",
MilestoneNumber: 1,
PerPage: &perPage,
Page: &page,
}
log.Print(label3.String())
items := make([]*label.CreateLabelResponse, 0)
for i := 0; i < 3; i++ {
items = append(items, &label.CreateLabelResponse{
Id: int64(i),
NodeId: "1233545",
Url: "https://api.github.com/repos/octocat/Hello-World/labels/bug",
Name: "octocat",
Description: "Hello-World",
Color: "#7f7f7f",
Default: true,
})
}
label4 := label.ListLabelResponse{
Code: 200,
Message: "OK",
Items: items,
}
log.Print(label4.String())
}
输出结果
name:"bug"
name:"bug" color:"12345" description:"hello"
id:208045946 node_id:"MDU6TGFiZWwyMDgwNDU5NDY=" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"bug" description:"Something isn't working" color:"f29513" default:true
owner:"zhang san" repo:"example" milestone_number:1 per_page:30 page:1
code:200 message:"OK" items:{node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true} items:{id:1 node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true} items:{id:2 node_id:"1233545" url:"https://api.github.com/repos/octocat/Hello-World/labels/bug" name:"octocat" description:"Hello-World" color:"#7f7f7f" default:true}
初步了解 ProtoBuf 的优缺点和使用的场景, 简单写了一些代码。