1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
|
|
相关推荐
1个回答
|
|
工作上有大量协议采用 Google Protocol Buffer,关于 Protobuf 的简单介绍可以看 IBM 的《Google Protocol Buffer 的使用和原理》这篇介绍。简单来说,Protobuf 的优点是(相比 XML)更小、更快、更简单,同时可以向后兼容。缺点的话,对我日常工作影响比较大的就是可读性较差,因为 Protobuf 压缩的时候会做序列化,生成 pb 文件,这个文件是二进制的,无法做到 human readable。但在日常工作中,尤其是排查问题是,经常需要看资源文件内容是否正确、上下游服务收发包内容是否正确、伪造 pb 资源等等,这些内容都是 pb 的,需要经过转换才能读懂,由此就用 Go 写了利用 JSON 伪造 pb 资源和反序列化 pb 打印成人类可读的文本的两段程序。
JSON 转 pb 这个感觉起来是件很麻烦的事情,但是有了 jsonpb 这个库之后,事情就变得很简单了。 首先定义 user.proto 。 syntax = “proto3”;package user_info;message UserInfo { message User { string username = 1; uint32 age = 2; string graduate = 3; } repeated User user_list = 1;} 然后再转换生成 user.pb.go 文件。 protoc --go_out=。 user.proto 编写 JSON 文件,注意 key 的名字需要遵循 user.pb.go 中的名字,例如: type UserInfo struct { UserList []*UserInfo_User `protobuf:“bytes,1,rep,name=user_list,json=userList” json:“user_list,omitempty”`}type UserInfo_User struct { Username string `protobuf:“bytes,1,opt,name=username” json:“username,omitempty”` Age uint32 `protobuf:“varint,2,opt,name=age” json:“age,omitempty”` Graduate string `protobuf:“bytes,3,opt,name=graduate” json:“graduate,omitempty”`} user.pb.go 已经指定了一个 field 在 JSON 中的命名,直接按照这个编写 JSON 文件即可。 { “userList”: [ { “username”: “lawrencelin”, “age”: 28, “graduate”: “Tongji University” }, { “username”: “findingsea”, “age”: 28, “graduate”: “Fudan University” } ]}编写主代码: package mainimport ( “github.com/golang/protobuf/proto” “io/ioutil” “os” “fmt” “github.com/golang/protobuf/jsonpb” “user_proto”)func main() { jsonFilePath := “/home/lawrence/GoglandProjects/JsonToPbIntro/json/user_info.json” pbFilePath := “/home/lawrence/GoglandProjects/JsonToPbIntro/pb/user_info.pb” buf, err := ioutil.ReadFile(jsonFilePath) if err != nil { fmt.Println(“Read file err: ”, err) os.Exit(0) } userInfo := &user_info.UserInfo{} if err = jsonpb.UnmarshalString(string(buf), userInfo); err != nil { fmt.Println(“jsonpb UnmarshalString fail: ”, err) os.Exit(0) } fmt.Println(“user info pb: ”, userInfo.String()) data, err := proto.Marshal(userInfo) if err != nil { fmt.Println(“proto Marshal fail: ”, err) os.Exit(0) } if err = ioutil.WriteFile(pbFilePath, data, os.ModePerm); err != nil { fmt.Println(“Write file err: ”, err) }} 核心函数就是 UnmarshalString ,输入是 JSON 字符串,输出 Protobuf 对象。 func UnmarshalString(str string, pb proto.Message) error 运行一下 main.go,就生成好了 user_info.pb 文件,打印如下: user info pb: user_list:《username:“lawrencelin” age:28 graduate:“Tongji University” 》 user_list:《username:“findingsea” age:28 graduate:“Fudan University” 》 打印 Protobuf 对象 这一边本来应该很简单的,因为 Protobuf 库就提供了字符串转换函数,像 C++ 版 Protobuf 直接提供了 DebugString() 方法,可以直接输出可读的打印字符串。但是 Go 里面,我直觉反应调用了一下 String() 方法,fmt.Println(“user info pb: ”, userInfo.String()),发现只能打印成一行。 user_list:《username:“lawrencelin” age:28 graduate:“Tongji University” 》 user_list:《username:“findingsea” age:28 graduate:“Fudan University” 》 看了一下 String() 方法的实现,直接调用了 CompactTextString 方法: func (m *UserInfo) String() string { return proto.CompactTextString(m) }// CompactText writes a given protocol buffer in compact text format (one line).func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }// CompactTextString is the same as CompactText, but returns the string directly.func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) } 注释里说明了这个接口只能返回压缩过的文本,这个可读性就很差了,那如何输出可读的 Protobuf 对象呢? 看了文档之后,发现应该使用 MarshalTextString 接口,就可以直接返回可读的文本格式 Protobuf 对象。其接口源码和注释如下: // MarshalText writes a given protocol buffer in text format.// The only errors returned are from w.func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }// MarshalTextString is the same as MarshalText, but returns the string directly.func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) } 调用的方法很简单,fmt.Println(proto.MarshalTextString(userInfo)),输出: user_list: 《 username: “lawrencelin” age: 28 graduate: “Tongji University”》user_list: 《 username: “findingsea” age: 28 graduate: “Fudan University” |
|
|
|
只有小组成员才能发言,加入小组>>
物联网工程师必备:怎么选择不同的无线连接技术,本指南帮你忙!
3283 浏览 1 评论
【DFRobot TinkerNode NB-IoT 物联网开发板试用连载】WIFI功能测试
3935 浏览 0 评论
【DFRobot TinkerNode NB-IoT 物联网开发板试用连载】Arduino的替代SublimeText3+STino
3442 浏览 0 评论
使用端口扩展器轻松高效地向IIoT端点添加具有成本效益的子节点
4004 浏览 1 评论
20681 浏览 11 评论
模组有时候复位重启后输出日志为“REBOOT_CAUSE_SECURITY_PMU_POWER_ON_RESET”的原因?
801浏览 2评论
1018浏览 2评论
1023浏览 1评论
1141浏览 1评论
380浏览 1评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 17:55 , Processed in 0.793221 second(s), Total 78, Slave 62 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号