版权声明:本文为博主原创文章,未经博主允许不得转载。
本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。
google 开源项目。序列化数据结构的方案(Json 、XML 也是),通常用于编写需要数据交换或者需要存储数据的程序。这套方案包含一种用于描述数据结构的接口描述语言(Interface Description Language)和一个生成器,用于生成描述该数据结构的不同编程语言的源代码。
序列化与反序列化:
序列化 : 将数据结构或对象转换成二进制串的过程
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
优缺点:
总结:
Protobuf 比 XML、Json 更小,更快,使用和维护更简单,但是使用范围不够广。
我们可以参照 Protobuf 官网 的指南进行尝试。选择 Basics: Java 查看 java 语言的用法。
2. 在 proto 文件夹下新建 test.proto 文件。
3. 从官网拷贝 demo 代码到 test.proto 文件。
//使用 proto2,目前有 proto2 和 proto3 这两个版本,他们语法有些不同,内核实现也有所区别。
syntax = "proto2";
package tutorial;
//生成 java 源文件的包名
option java_package = "com.example.tutorial";
//生产 java 源文件的类名
option java_outer_classname = "AddressBookProtos";
//message 相当与 java 的 class
message Person {
//required 必须设置(不能为null)
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 重复的(也就是指集合)
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
这是一段 protobuf 的源文件,我们需要使用 protobuf 的编译器进行编译。
4. 编译 protobuf 代码,这边有两种方案进行编译。
(1)手动编译
手动编译的时候,我们需要先拿到编译器。github 下载地址
这边下载时 win64 版本,解压出来后,在 bin 目录下有 protoc.exe ,我们使用这个进行编译。
命令:
protoc -I=生成 java 源文件的目录 --java_out=. proto源文件
(这边把 proto.exe 和 test.proto 拷贝到 D:\proto 下面,这个指令是生成 java 的源文件,修改指令,也可以生成其他源文件)
运行结果:
在 com 包一直往下点,可以发现生成一个 AddressBookProtos.java 的 java 源文件。
(2)使用 AS 插件
使用谷歌提供的 gradle 插件 进行编译。
在项目下的 build.gradle 中添加 classpath。
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
在 app 下的 build.gradle 中引用插件,配置参数,以及进行依赖。
引用插件:
apply plugin: 'com.google.protobuf'
配置参数:
protobuf {
protoc {
// You still need protoc like in the non-Android case
artifact = 'com.google.protobuf:protoc:3.0.0'
}
plugins {
javalite {
// The codegen for lite comes as a separate artifact
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
}
generateProtoTasks {
all().each { task ->
task.builtins {
// In most cases you don't need the full Java output
// if you use the lite output.
remove java
}
task.plugins {
javalite { }
}
}
}
}
进行依赖:
implementation 'com.google.protobuf:protobuf-lite:3.0.0'
这样 AS 就会自动帮我们进行编译前面编写的 proto 文件。
5. 运行 Make Modele app。
运行完成之后,我们可以在 build 文件夹下,找到 proto 生成的源文件。
6. 编写代码使用。
MainActivity :
public class MainActivity extends AppCompatActivity {
private final static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AddressBookProtos.Person.PhoneNumber.Builder phoneNumber = AddressBookProtos.Person.PhoneNumber
.newBuilder().setNumber("13511111111");
AddressBookProtos.Person.Builder person = AddressBookProtos.Person.newBuilder()
.setName("张三").setId(1).addPhones(phoneNumber);
AddressBookProtos.Person.PhoneNumber.Builder phoneNumber1 = AddressBookProtos.Person.PhoneNumber
.newBuilder().setNumber("13522222222");
AddressBookProtos.Person.Builder person1 = AddressBookProtos.Person.newBuilder()
.setName("李四").setId(1).addPhones(phoneNumber1);
AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder()
.addPeople(person).addPeople(person1)
.build();
//保存为一个文件或者需要向服务器发送
//序列化,将对象转成 byte 数组
long l = System.currentTimeMillis();
byte[] bytes = addressBook.toByteArray();
Log.e(TAG, "111 zx protobuf 序列化耗时:" + (System.currentTimeMillis() - l));
Log.e(TAG, "111 zx protobuf 序列化数据大小:" + bytes.length);
//从文件读到内存或者解析从服务器返回的数据
//反序列化
try {
l = System.currentTimeMillis();
AddressBookProtos.AddressBook addressBook1 = AddressBookProtos.AddressBook.parseFrom
(bytes);
Log.e(TAG, "111 zx protobuf 反序列化耗时:" + (System.currentTimeMillis() - l));
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
}
}
这是上面代码运行的结果,我们按照同样的数据格式,同样的数据,对 Json 进行比较。
AddressBook :
public class AddressBook {
List persons;
public AddressBook() {
this.persons = new ArrayList<>();
}
public void addPersons(Person person) {
persons.add(person);
}
public List getPersons( ) {
return persons;
}
}
Person :
public class Person {
private String name;
private int id;
private String email;
private List phones;
public Person() {
phones = new ArrayList<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void addPhones(PhoneNumber number){
phones.add(number);
}
public List getPhones() {
return phones;
}
}
PhoneNumber :
public class PhoneNumber {
enum PhoneType {
MOBILE,
HOME,
WORK;
}
private String number;
private PhoneType type;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public PhoneType getType() {
return type;
}
public void setType(PhoneType type) {
this.type = type;
}
}
编写 JsonTest ,分别使用 gson 和 fastjson 进行测试。
JsonTest :
public class JsonTest {
private static final String TAG = "JsonTest";
public static void fastJson() {
AddressBook addressBook = getObject();
long l = System.currentTimeMillis();
String data = JSON.toJSONString(addressBook);
byte[] bytes = data.getBytes();
Log.e(TAG, "111 zx FastJson 序列化耗时:" + (System.currentTimeMillis() - l));
Log.e(TAG, "111 zx FastJson 序列化数据大小:" + bytes.length);
l = System.currentTimeMillis();
AddressBook addressBook1 = JSON.parseObject(new String(bytes), AddressBook.class);
Log.e(TAG, "111 zx FastJson 反序列化耗时:" + (System.currentTimeMillis() - l));
}
public static void gson(){
AddressBook addressBook = getObject();
long l = System.currentTimeMillis();
Gson gson = new Gson();
String data = gson.toJson(addressBook);
byte[] bytes = data.getBytes();
Log.e(TAG, "111 zx Gson 序列化耗时:" + (System.currentTimeMillis() - l));
Log.e(TAG, "111 zx Gson 序列化数据大小:" + bytes.length);
l = System.currentTimeMillis();
AddressBook addressBook1 = gson.fromJson(new String(bytes), AddressBook.class);
Log.e(TAG, "111 zx Gson 反序列化耗时:" + (System.currentTimeMillis() - l));
}
private static AddressBook getObject(){
AddressBook addressBook = new AddressBook();
PhoneNumber p_110 = new PhoneNumber();
p_110.setNumber("110");
Person zs = new Person();
zs.setId(1);
zs.setName("张三");
zs.addPhones(p_110);
addressBook.addPersons(zs);
PhoneNumber p_120 = new PhoneNumber();
p_120.setNumber("120");
Person ls = new Person();
ls.setId(2);
ls.setName("李四");
ls.addPhones(p_120);
addressBook.addPersons(ls);
return addressBook;
}
}
结果:
可以发现,不论序列化耗时、序列化后数据大小、反序列化,protobuf 都有明显的优势。
代码链接