一 FlatBuffer使用原有
在做 Android 開發的時候,JSON 是最常用的數據序列化技術。JSON 的可讀性很強,但是序列化和反序列化性能卻是最差的。解析的時候,JSON 解析器首先,需要在內存中初始化一個對應的數據結構,這個事件經常會消耗 100ms ~ 200ms2;解析過程中,要產生大量的臨時變量,造成 Java 虛擬機的 GC 和內存抖動,解析 20KB 的數據,大概會消耗 100KB 的臨時內存2。FlatBuffers 就解決了這些問題
二 FlatBuffer
FlatBuffers 是一個開源的跨平臺數據序列化庫,可以應用到幾乎任何語言(C++, C#, Go, Java, JavaScript, PHP, Python),最開始是 Google 爲遊戲或者其他對性能要求很高的應用開發的。項目地址在 GitHub 上。官方的文檔在 這裏。
- 直接讀取序列化數據,而不需要解析(Parsing)或者解包(Unpacking):FlatBuffer 把數據層級結構保存在一個扁平化的二進制緩存(一維數組)中,同時能夠保持直接獲取裏面的結構化數據,而不需要解析,並且還能保證數據結構變化的前後向兼容
- 高效的內存使用和速度:FlatBuffer 使用過程中,不需要額外的內存,幾乎接近原始數據在內存中的大小
- 靈活:數據能夠前後向兼容,並且能夠靈活控制你的數據結構。
- 很少的代碼侵入性:使用少量的自動生成的代碼即可實現。
- 強數據類性,易於使用,跨平臺,幾乎語言無關。
性能對比
三 使用
1 編寫Model對應的fbs文件
Items.fbs
namespace com.bpj.optimization.optimization.lsn13;
table Items {
ItemId : long;
timestemp : int;
basic:[Basic];
}
table Basic{
id:int;
name:string;
email:int;
code:long;
isVip:bool;
count:int;
carList:[Car];
}
table Car{
id:long;
number:long;
describle:string;
}
root_type Items;
2 當前目錄下,命令行編譯生成java文件
flatc -j -b fbs文件名.fbs
生成對應的java文件:
3 拷貝java文件到項目中使用
同時拷貝的還有庫提供的FlatBufferBuilder.java 和Table.java文件,修改報錯
4 使用
public void serialize(View v) {
new Thread(new Runnable() {
@Override
public void run() {
//==================序列化========================
FlatBufferBuilder builder = new FlatBufferBuilder();
int id1 = builder.createString("蘭博基尼");
//準備Car對象
int car1 = Car.createCar(builder, 10001L, 88888L, id1);
int id2 = builder.createString("奧迪A8");
//準備Car對象
int car2 = Car.createCar(builder, 10001L, 88888L, id2);
int id3 = builder.createString("奧迪A9");
//準備Car對象
int car3 = Car.createCar(builder, 10001L, 88888L, id3);
int[] cars = new int[3];
cars[0] = car1;
cars[1] = car2;
cars[2] = car3;
//創建Basic對象裏面的Car集合
int carList = Basic.createCarListVector(builder, cars);
int name = builder.createString("ray");
int email = builder.createString("[email protected]");
int basic = Basic.createBasic(builder, 10, name, email, 100L, true, 100, carList);
int basicOffset = Items.createBasicVector(builder, new int[]{basic});
/**
* table Items {
ItemId : long;
timestemp : int;
basic:[Basic];
}
*/
Items.startItems(builder);
Items.addItemId(builder, 1000L);
Items.addTimestemp(builder, 2016);
Items.addBasic(builder, basicOffset);
int rootItems = Items.endItems(builder);
Items.finishItemsBuffer(builder, rootItems);
//============保存數據到文件=================
if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){
Log.e(TAG, "sdcard un MEDIA_MOUNTED");
}
File sdcard = Environment.getExternalStorageDirectory();
//保存的路徑
File file = new File(sdcard, "Items.txt");
if (file.exists()) {
file.delete();
}
ByteBuffer data = builder.dataBuffer();
FileOutputStream out = null;
FileChannel channel = null;
try {
out = new FileOutputStream(file);
channel = out.getChannel();
while (data.hasRemaining()) {
channel.write(data);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (channel != null) {
channel.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//===================反序列化=============================
FileInputStream fis = null;
FileChannel readChannel = null;
try {
fis = new FileInputStream(file);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
readChannel = fis.getChannel();
int readBytes = 0;
while ((readBytes = readChannel.read(byteBuffer)) != -1) {
System.out.println("讀取數據個數:" + readBytes);
}
//把指針回到最初的狀態,準備從byteBuffer當中讀取數據
byteBuffer.flip();
//解析出二進制爲Items對象。
Items items = Items.getRootAsItems(byteBuffer);
//讀取數據測試看看是否跟保存的一致
Log.i(TAG, "items.id:" + items.ItemId());
Log.i(TAG, "items.timestemp:" + items.timestemp());
Basic basic2 = items.basic(0);
Log.i(TAG, "basic2.name:" + basic2.name());
Log.i(TAG, "basic2.email:" + basic2.email());
//carList
int length = basic2.carListLength();
for (int i = 0; i < length; i++) {
Car car = basic2.carList(i);
Log.i(TAG, "car.number:" + car.number());
Log.i(TAG, "car.describle:" + car.describle());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (readChannel != null) {
readChannel.close();
}
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}