Protobuf详解使用

Protobuf全称是Google Protocol Buffer,是一种高效轻便的结构化数据存储方式,可用于(数据)通信协议、数据存储等。

Xml、Json是目前常用的数据交换格式,它们直接使用字段名称维护序列化后类实例中字段与数据之间的映射关系,一般用字符串的形式保存在序列化后的字节流中。消息和消息的定义相对独立,可读性较好。但序列化后的数据字节很大,序列化和反序列化的时间较长,数据传输效率不高。
xml、json是用字段名称来确定类实例中字段之间的独立性,所以序列化后的数据多了很多描述信息,增加了序列化后的字节序列的容量。
Protobuf和Xml、Json序列化的方式不同,采用了二进制字节的序列化方式,序列化与反序列化不需要解析相应的节点属性和多余的描述信息,用字段索引和字段类型通过算法计算得到字段之前的关系映射,从而达到更高的时间效率和空间效率,特别适合对数据大小和传输速率比较敏感的场合使用。
结论
protobuf是由字段索引(fieldIndex)与数据类型(type)计算(fieldIndex<<3|type)得出的key维护字段之间的映射且只占一个字节,所以相比json与xml文件,protobuf的序列化字节没有过多的key与描述符信息,所以占用空间要小很多。直接是2进数据序列化与反序列化不需要解析相应的节点属性和多余的描述信息所以时间效率要高。

  • 优势
    与语言无关,平台无关
    Protobuf支持Java, C++, Python等多种语言,支持多个平台。
    高效
    比XML,Json更小(3~10倍),更快(20 ~ 100倍),更为简单。
    扩展性,兼容性好
    你可以更新数据结构,而不影响和破坏原有的旧程序。

  • 缺点
    二进制格式导致可读性差(二进制格式)
    缺乏自描述

  • 序列化反序列化:

序列化:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
反序列化:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
作用:将数据结构或对象转换成能够被存储和传输(例如网络传输)的格式,同时应当要保证这个序列化结果在之后(可能是另一个计算环境中)能够被重建回原来的数据结构或对象。

pb与xml Json比较
protobuf 数据类型
在这里插入图片描述
repeated 数组/集合 repeated User users = 1
Protobuf 使用

  • 创建.proto文件,定义数据结构
    protobuf将一种结构称为一个message类型
message Person {
  required string name = 1;
  required int32 id = 2; [default = 0]
  optional string email = 3;

  repeated int32 samples = 4 

}

其中Person是message这种结构的名称,name、id、email是其中的Field,每个Field保存着一种数据类型,后面的1、2、3是Filed对应的数字id。id在115之间编码只需要占一个字节,包括Filed数据类型和Filed对应数字id,在162047之间编码需要占两个字节,所以最常用的数据对应id要尽量小一些。

Field最前面的required,optional,repeated是这个Filed的规则,分别表示该数据结构中这个Filed有且只有1个,可以是0个或1个,可以是0个或任意个。optional后面可以加default默认值,如果不加,数据类型的默认为0,字符串类型的默认为空串。repeated后面加[packed=true]会使用新的更高效的编码方式。
引用其它message类在同一个文件中,可以直接引用定义过的message类型。在同一个项目中,可以用import来导入其它message类

  • message 类型都有一个或多个具有唯一编号的字段,每个字段都有一个名称和一个值类型,其中值类型可以是数字(整数或浮点数),布尔值,字符串,原始字节,甚至(如上例所示)其它 protocol buffer message 类型

  • message具有的字段,形式为:

message xxx {
  // 字段规则:required -> 字段只能也必须出现 1 次
  // 字段规则:optional -> 字段可出现 0 次或多次
  // 字段规则:repeated -> 字段可出现任意多次(包括 0)
  // 类型:int32、int64、sint32、sint64、string、32-bit ....
  // 字段编号:0 ~ 536870911(2 28-1)(除去 19000 到 19999 之间的数字)
  字段规则 类型 名称 = 字段编号;
}
import "myproject/other_protos.proto";
  • 在另一个文件中,import 这个proto之后,可以对Person这个message进行扩展。
extend Person {
  optional int32 bar = 126;
}

一旦定义了 messages,就可以在 .proto 文件上运行 protocol buffer 编译器来生成指定语言的数据访问类。这些类为每个字段提供了简单的访问器(如 name()和 set_name()),以及将整个结构序列化为原始字节和解析原始字节的方法 - 例如,选择的语言是 Java,则运行编译器上面的例子将生成一个名为 Person 的类。然后,你可以在应用程序中使用此类来填充,序列化和检索 Person 的 messages。于是你可以写一些这样的代码:

person = Person.newBuilder() ;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");

你的 .proto 文件将生成什么?
当你在 .proto 上运行 protocol buffer 编译器时,编译器将会生成所需语言的代码,这些代码可以操作文件中描述的 message 类型,包括获取和设置字段值、将 message 序列化为输出流、以及从输入流中解析出 message。

对于 C++,编译器从每个 .proto 生成一个 .h 和 .cc 文件,其中包含文件中描述的每种 message 类型对应的类。
对于 Java,编译器为每个 message 类型生成一个 .java 文件(类),以及用于创建 message 类实例的特殊 Builder 类。
Python 有点不同 - Python 编译器生成一个模块,其中包含 .proto 中每种 message 类型的静态描述符,然后与元类一起使用以创建必要的 Python 数据访问类。
对于 Go,编译器会生成一个 .pb.go 文件,其中包含对应每种 message 类型的类型。

1、在project的build.gradle中配置

 dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.2'
    }

2、在app的build.gradle中配置

apply plugin: 'com.android.application'
apply plugin: 'com.google.protobuf'

android {
    sourceSets {
        main {
            proto {
                //main目录新建proto目录
                srcDir 'src/main/proto'
                include '**/*.proto'
            }
            java {
                srcDir 'src/main/java'
            }
        }
    }
}

//构建task
protobuf {
    protoc {
        artifact = 'com.google.protobuf:protoc:3.1.0'
    }

    generateProtoTasks {
        all().each { task ->
            task.builtins {
                remove java
            }
            task.builtins {
                java {}
                // Add cpp output without any option.
                // DO NOT omit the braces if you want this builtin to be added.
                cpp {}
            }
        }
    }
    //生成目录
    generatedFilesBaseDir = "$projectDir/src/generated"
}

dependencies {
    compile 'com.google.protobuf:protobuf-java:3.1.0'
    compile 'com.google.protobuf:protoc:3.1.0'
}

3、Android studio 安装插件
在这里插入图片描述

其他语言
使用Protobuf前首先需要准备protobuf需要的Jar包以及在windows下的可执行文件(protoc.exe)通过protoc生成对应文件使用。
例如:
在命令行中定位到protoc.exe所在文件夹,执行“protoc --java_out ./ *.proto”命令
在这里插入图片描述

在Android中调用

1.将protobuf需要的Jar包导入到项目中

2.将生成的java文件拷贝到项目中对应的包下,就可以直接调用了
ProtoInfo info= ProtoInfo.newBuilder().setId(1001).setName(“jack”).build();

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值