您的位置:首页 > 编程语言 > Go语言

Google Protobuf编解码(序列化/反序列化)框架

2017-04-05 00:00 169 查看
编码/解码在Java中又称序列化/反序列化,Java本身的序列化反序列化技术生成的二进制码流太大,且转化效率低下,一般不适用于远程跨节点调用的编码框架。

Protobuf全称Protocol Buffers,由谷歌开源而来,特点如下:

码流小、效率高

语言平台无关,不只Java可以用,C++、python亦可

使用数据描述文件,可自动生成代码

和Facebook Thirft对比,Protobuf并不需要完全在开始就完全定义好全部结构,而可以在后期extends之前的结构,并且仍然可以读取之前结构编码的信息

使用步骤:

编写.proto类定义文件

通过提供的编译器产生对应的Java类

使用提供的API读写信息

1、编写.proto类定义文件

package tutorial;

option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;

enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}

message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}

repeated PhoneNumber phones = 4;
}

message AddressBook {
repeated Person people = 1;
}


文件说明:

package用于区分同名文件,在java_package缺省时,就是产生的bean的包

java_outer_classname指定包含文件中定义的所有类的类,如果缺省,会自动将.proto文件名设为类名

message定义一个类,message中可以包含message

每个属性后面的 =1、=2等数字是在二进制化数据时,属性的“唯一标识”,在每个message中独立编号

支持的修饰符:

required:标识必须被提供的字段,如果required字段的值没有被提供,编码解码时都会跑出异常;

optional:标识可以提供或不提供的字段,如果不提供,则返回默认值。默认值和java中相似,但是“子message”的字段会全部为空。默认值也可以用[default = value]进行设置;

repeated:标识ArrayList

每个属性后面的 =1、=2等数字,注意0-15比之后的数字再序列化时少一个字节,固0-15一般用在required和repeated字段上

支持的数据类型:
bool
,
int32
,
float
,
double,
string
,
enum

.proto TypeNotesC++ TypeJava TypePython TypeGo Type
doubledoubledoublefloat*float64
floatfloatfloatfloat*float32
int32虽然可以有负数,但是效率不高int32intint*int32
int64虽然可以有负数,但是效率不高int64longint/long[3]*int64
uint32无符号整数,只能是正数uint32intint/long[3]*uint32
uint64无符号整数,只能是正数uint64longint/long[3]*uint64
sint32有符号整数,表示负数的效率更高int32intint*int32
sint64有符号整数,表示负数的效率更高int64longint/long[3]*int64
fixed32永远占据4个字节,如果超过256的话,效率更高uint32intint*uint32
fixed64永远占据8个字节,如果超过256的话,效率更高uint64longint/long[3]*uint64
sfixed32永远占据4个字节int32intint*int32
sfixed64永远占据8个字节int64longint/long[3]*int64
boolboolbooleanbool*bool
string字符串必须是UTF-8或者7-bit ASCII。stringStringstr/unicode*string
bytesstringByteStringstr[]byte
备注:

[3] Python3中不再有int和long之分,而只有不限长度的整型int。

2、通过提供的编译器产生对应的Java类

2.1、将protoc.exe和对应的.proto文件放到项目所在的java文件夹下





protoc.exe --java_out=.\ .\Request.proto

就可以在上面的proto文件中的java_package描述的位置产生指定的文件

3、使用提供的API读写信息

public class TestSubscribeReqProto {
/**
* 1、构建对象
* @return
*/
public static SubscribeReqProto.SubscribeReq createSubscribeReq(){
SubscribeReqProto.SubscribeReq.Builder builder =
SubscribeReqProto.SubscribeReq.newBuilder();
builder.setSubReqID(1);
builder.setUserName("caizhijie");
builder.setProductName("Yellow Book");
List<String> address = new ArrayList<>();
address.add("NanJing YuHuaTai");
address.add("BeiJing ZhiJinCheng");
address.add("ShenZhen HongShuLin");
builder.addAllAddress(address);
return builder.build();
}

/**
* 2、编码
* @param req
* @return
*/
public static byte[] encode(SubscribeReqProto.SubscribeReq req){
return req.toByteArray();
}

/**
* 3、解码
* @param body
* @return
* @throws InvalidProtocolBufferException
*/
public static SubscribeReqProto.SubscribeReq decode(byte[] body) throws InvalidProtocolBufferException {
return SubscribeReqProto.SubscribeReq.parseFrom(body);
}

public static void main(String[] args) throws InvalidProtocolBufferException {
SubscribeReqProto.SubscribeReq req = createSubscribeReq();
System.out.println("Before encode : "+req.toString());
SubscribeReqProto.SubscribeReq req2 = decode(encode(req));
System.out.println("After encode : "+req2.toString());
System.out.println("Assert equal : -->" + req2.equals(req));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java Google ProtoBuf