Protobuf学习笔记

Posted by iamxhuon 2012/05/22 Leave a comment (0)Go to comments

Protocol buffers是什么?

首先了解一下Protocol Buffers(简称ProtoBuf)是什么?官网对它的定义如下:

Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler.

上述定义描述了Protocol Buffers的全部优点:语言无法,平台无关,可扩展,用于序列化结构化数据。在官方定义之外我认为protobuf一种通用结构化组织数据描述语言,拥有一整套的简单语法规则,内置的类型系统等等。因此在学习过程中,可以把它当作一门简单的语言来看待。Protocol Buffers定义了描述文件的结构,而描述文件结构的语法检查,类型检查则需要protoc来处理,这时protoc就是一个编译器,在编译过程中不但检查语法还负责生成指定格式的目标文件。
Protocol Buffers为以.proto文件生成的各种对象(不限语言)的提供一致的序列化手段,保证数据最终持久化后的格式一致。而需要序列化的数据,由用户根据.proto文件提供的类,创建相应的对象。

Protobuf的描述文件 proto

在使用Protobuf时,定义描述文件是最重要的事情。Protobuf描述文件格式如下:

/*** Created by IntelliJ IDEA.* User: huxing(xing.hu@360hqb.com)* Date: 12-5-22* Time: 下午2:22*/
package org.colorfuldays.ssm.domain.protobuf;option java_package = "org.colorfuldays.ssm.domain.protobuf";message User{optional int64 id = 1;optional string name = 2;optional string password = 3;
}message book{optional int64 id = 1;optional string name = 2;optional string isbn = 3;repeated User author = 4;optional int64 publish_date = 5;
}

  • proto文件结构
    从上面的代码可以看出,proto文件的结构非常简单。
    package java_package 定义生成的java类的package名称。
    message定义一种类型,类型以Java中的一个class,book是类名,在生成Java代码时,就是使用这个类名。
    接下来是该类型中包含的字段,字段包括 [限定符 类型 字段名称 = tag [default = 默认值]]
  • protobuf支持的类型
    protobuf支持的默认类型如下

    .proto Type Notes C++ Type Java Type
    double   double double
    float   float float
    int32 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint32 instead. int32 int
    int64 Uses variable-length encoding. Inefficient for encoding negative numbers – if your field is likely to have negative values, use sint64 instead. int64 long
    uint32 Uses variable-length encoding. uint32 int1
    uint64 Uses variable-length encoding. uint64 long1
    sint32 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s. int32 int
    sint64 Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s. int64 long
    fixed32 Always four bytes. More efficient than uint32 if values are often greater than 228. uint32 int1
    fixed64 Always eight bytes. More efficient than uint64 if values are often greater than 256. uint64 long1
    sfixed32 Always four bytes. int32 int
    sfixed64 Always eight bytes. int64 long
    bool   bool boolean
    string A string must always contain UTF-8 encoded or 7-bit ASCII text. string String
    bytes May contain any arbitrary sequence of bytes. string ByteString

除此之外,还支持枚举,自定义类型等。使用方式见上面代码示例。更详细的介绍见官方文档
protobuf的自定义类型,支持对象组合方式,在CPP中使用较少,在Java中广泛采用,但是目前我们需要序列化的对象是瘦模型,用不上这种特性。

  • protobuf的限定符
  • required 必填项,如果该项不设值,在序列化时会抛出RuntimeException,推荐不使用该字段,该字段一旦使用,无法更改。不利于以来的扩展
  • optional 不存在时使用默认值,默认值可自定义。系统默认值如下:int = 0,bool = false,string=”"
  • repeated 类似于Java中的List,在实际生成Java类时,也是生成一个List来表示
  • tag说明
    tag 的主要作用是用来标识每一个field,序列化时会使用tag,取值为数字。如上面的id = 1,其中的1,即为tag。
    在protobuf序列化encode时标识每一个field,0-15比16-少一个byte,优化时可以使用到。
  • default值
    proto文件中定义的默认值在处理版本兼容时非常有用,下面会做相关介绍。
  • guide style
    Protocol Buffers官方提供了一个Guide Style。其中介绍了一些定义proto的优秀实践。一句话总结就是名称时,message名称以驼峰方式定义,字段名则需要以如author_name方式定义。字段名在生成Java代码时,会自动转换为符合Java风格的命名方式。

如何在项目中组织proto文件,暂时能想到下面三种方式:
1、一个项目中所有的class都在一个*.proto中定义?
2、每个class作为单独的文件?
3、按模块划分.proto文件
目前还没有确认哪种方式更佳。

Protobuf 生成的对象及序列化

Protobuf 生成的Java对象是immutable的,生成后无法修改,生成的Java对象以Builder方式构建,在调用Builder时为field设值。

  • 序列化方法
    Java接口提供的序列化相关方法如下:

    byte[] toByteArray();: serializes the message and returns a byte array containing its raw bytes.
    static Person parseFrom(byte[] data);: parses a message from the given byte array.
    void writeTo(OutputStream output);: serializes the message and writes it to an OutputStream.
    static Person parseFrom(InputStream input);: reads and parses a message from an InputStream.

    在处理序列化及反序列化对象时,发现难于对序列化方法的抽象,因为上述几个方法都不是public的。因此在序列化对象时,需要针对每一个Java对象实现其特定的序列化类。

扩展问题

Protobuf提供了极佳的扩展性,在扩展时,必须满足下面的要求:

  • you must not change the tag numbers of any existing fields.
  • you must not add or delete any required fields.
  • you may delete optional or repeated fields.
  • you may add new optional or repeated fields but you must use fresh tag numbers (i.e. tag numbers that were never used in this protocol buffer, not even by deleted fields).

在扩展之后可以实现下面的世界通
旧的系统可以读新的数据,但是无法读取到新添加的内容
新的系统可以读旧的数据,读不到的新加元素使用默认值

  旧数据 新数据
旧系统 不变 忽略新添加的字段
新系统 不存在的字段取默认值,删除的字段取默认值, 无变化
缺点:

Protobuf无疑是一个非常优秀的结构化数据序列化协议,现在我们来说一说在Java环境下,它的一些缺点:
1、不支持大数据集的处理,少于1M
2、不支持Date,Map这些Java内建的对象

更多详细信息请参照官方文件https://developers.google.com/protocol-buffers/docs

Protobuf学习笔记相关推荐

  1. 冰冰学习笔记:简单了解protobuf

    欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...

  2. Go语学习笔记 - grpc server/client protobuf | 从零开始Go语言

    目录 创建Proto文件 生成proto文件对应的go文件 创建服务结构体 创建客户端测试 小结 学习笔记,写到哪是哪. 上一篇是写的redis操作来着,最近主要研究了一下grpc. 在玩grpc的过 ...

  3. Caffe学习笔记4图像特征进行可视化

    Caffe学习笔记4图像特征进行可视化 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit201 ...

  4. Caffe 学习笔记1

    Caffe 学习笔记1 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和 ...

  5. 《Go语言圣经》学习笔记 第四章 复合数据类型

    <Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...

  6. Apollo学习笔记

    Apollo学习笔记 Apollo课程 智能驾驶入门课程 无人驾驶概览 1.软件层分为三层: 实时操作系统(RTOS):确保在给定时间内完成特定任务,实时时确保系统稳定性.驾驶安全性的重要要求.通过在 ...

  7. SLAM学习笔记(十九)开源3D激光SLAM总结大全——Cartographer3D,LOAM,Lego-LOAM,LIO-SAM,LVI-SAM,Livox-LOAM的原理解析及区别

    本文为我在浙江省北大信研院-智能计算中心-情感智能机器人实验室-科技委员会所做的一个分享汇报,现在我把它搬运到博客中. 由于参与分享汇报的同事有许多是做其他方向的机器人工程师(包括硬件.控制等各方面并 ...

  8. 视觉学习笔记6——YOLOv5(v6.2)部署与代码理解

    文章目录 前言 一.YOLOv5是什么? 二.环境搭建 1.基本环境 2.特殊环境 三.自定义训练 模型训练 模型测试 四.源码个人理解 1.detect.py文件 2.yolo.py文件 3. tr ...

  9. Go语学习笔记 - websocket gorilla(附测试代码) | 从零开始Go语言

    目录 项目结构 消息结构 服务端代码 定义客户端行为 服务启动 测试代码 总结 学习笔记,写到哪是哪. websocket也是常用的协议了,在上一篇中主要测试使用了一下grpc. 下面我会把代码贴出来 ...

最新文章

  1. MockDialog
  2. 一.js高级(4)-函数调用-this指向-其他参数
  3. winform中捕获程序未处理的所有异常
  4. python使用环境_使用python之环境管理
  5. php 写一个水仙花数的函数
  6. 索引原理及项目中如何使用索引实例分析
  7. mac系统在云服务器地址,mac如何登陆云服务器地址
  8. 论文笔记:Person Re-identification with Deep Similarity-Guided Graph Neural Network
  9. ubuntu-桌面菜单栏、任务栏、标题栏都不见了-解决办法
  10. 纯新手DSP编程--5.31--硬件中断管理
  11. 2014中国高校SAS数据分析大赛拉开帷幕
  12. Linux 常用命令 权限管理命令
  13. 尔雅 2017大学计算机基础答案,2018超星尔雅大学计算机基础答案
  14. kdj指标主要看哪个值_史上最全KDJ指标用法详解,学习KDJ指标看这一篇就够了
  15. android 桌面操作系统,Android主题美化: Win7桌面完成版Android Seven Pro V2
  16. 【英语语法入门】 第13讲 形容词
  17. [转载]使用 JDBC 连接不同版本 DB2 数据库的兼容性问题
  18. 哎呀你不要把他叫出来_墓友-第一章——釉彩瓶-爱阅小说网
  19. (附源码)spring boot学科竞赛活动报名系统 毕业设计 012239
  20. Arcgis使用教程(六)ARCGIS空间数据查询

热门文章

  1. 【C】printf按8进制、10进制、16进制输出以及高位补0
  2. HD-SDI光端机有哪些优势?
  3. 【渝粤教育】国家开放大学2018年秋季 1167t环境水利学 参考试题
  4. 【渝粤题库】广东开放大学 信息安全数学基础 形成性考核 (2)
  5. 亿佰特串口服务器接入阿里云MQTT协议的软件配置教程
  6. linux alsa 音频管理,在Linux上的高级音频控制
  7. ckfinder php 配置,php – 在Laravel 5中为CKEditor设置路径以使用CKFinder
  8. openmv串口发送数据_关于arduino和openmv串口通信的问题
  9. linux操作系统学什么,Linux学习-第一天-什么是操作系统
  10. html怎么把一段文字设置为连接到下一个网页的按钮,网页设计三合一模拟试题(一)...