proto3序列化很好用,在原來開發APP存資料到日志時,日志文檔半小時可達300M,資料量大時對性能有很大影響,是以改用proto序列化存儲資料,經測試性能有所提升,日志大小為原來三分之一,是以優勢還是很明顯的。
但proto3序列化多條消息到檔案時,按官方文檔介紹,反序列化時是沒法區分一個完整對象序列化資料的界限的,也就是沒有分隔符,是以需要自己設定分隔符,反序列化時按規則解即可,以下是基于上一篇文章中環境的案例
一、多消息持續序列化規則
每個對象序列化後位元組數的長度作為序列化内容前置4個位元組的資料,即若一條序列化資料長度為100個位元組,那麼前這個資料前加4個位元組,這4個位元組的内容是100,那麼總長度就是104個位元組,依此規則持續序列化到檔案即可
二、定義proto資料結構
syntax = "proto3";
package tutorial;
message Person {
string name = 1;
int32 id = 2;
string email = 3;
string phone = 4;
}
三、序列化測試
/**
* 序列化
*
* @param path
*/
private void serializeProto(String path) {
System.out.println("serialize file " + path);
try {
OutputStream outputStream = new FileOutputStream(new File(path));
byte[] data;
for (int i = 0; i < 10; i++) {
Message.Person person = Message.Person.newBuilder().setId(i)
.setEmail(String.valueOf(i)).setName(String.valueOf(i)).setPhone(String.valueOf(i)).build();
byte[] dataByte = person.toByteArray();
byte[] lenByte = ProtoHelper.intToByteArray(dataByte.length);
data = new byte[dataByte.length + lenByte.length];
System.arraycopy(lenByte, 0, data, 0, lenByte.length);
System.arraycopy(dataByte, 0, data, lenByte.length, dataByte.length);
outputStream.write(data);
System.out.println("serialize len :" + dataByte.length + ",id:" + person.getId() + ",name:" + person.getName() + ",email:" + person.getEmail() + ",phone:" + person.getPhone());
}
outputStream.flush();
outputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
四、反序列化
因為上述資料量小,這裡一次性從檔案讀出來,就沒有設定緩沖區了
/**
* 反序列化
* @param path
*/
public void deSerializeProto(String path) {
System.out.println("deSerialize file " + path);
try {
InputStream inputStream = new FileInputStream(new File(path));
byte[] data = new byte[4096];
int len = 0;
while ((len = inputStream.read(data)) > 0) {
int index = 0;
while (index < len) {
byte[] lenByte = new byte[4];
System.arraycopy(data, index, lenByte, 0, 4);
int itemLen = ProtoHelper.byteArrayToInt(lenByte);
byte[] dataByte = new byte[itemLen];
System.arraycopy(data, index + lenByte.length, dataByte, 0, itemLen);
Message.Person person = Message.Person.parseFrom(dataByte);
System.out.println("deSerialize len :" + (dataByte.length + 4) + ",id:" + person.getId() + ",name:" + person.getName() + ",email:" + person.getEmail() + ",phone:" + person.getPhone());
index = index + lenByte.length + dataByte.length;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
執行結果:

由于proto跨平台,是以java端序列化後,C端同僚也能解碼檔案,有一定的日志安全性吧