FlatBuffers是Google開源的一個跨平臺的、高效的、提供了C++/Java接口的序列化工具庫,它是Google專門爲遊戲開發或其餘性能敏感的應用程序需求而建立。尤爲適用移動,嵌入式平臺,這些平臺在內存大小及帶寬相比桌面系統都是受限的,而應用程序好比遊戲又有更高的性能要求。它將序列化數據存儲在緩存中,這些數據既能夠存儲在文件中,又能夠經過網絡原樣傳輸,而不須要任何解析開銷。如下是項目地址: 代碼託管主頁:github.com/google/flat… 項目介紹主頁:google.github.io/flatbuffers…html
相比傳統的JSON和Protocol Buffers等序列化工具,FlatBuffers具備以下的一些優勢:java
Protocol Buffers的確和FlatBuffers比較相似,但其主要區別在於FlatBuffers在訪問數據前不須要解析/拆包這一步,並且Protocol Buffers既沒有可選的文本導入/導出功能,也沒有Schemas語法特性(好比union)。git
JSON是一種輕量級的數據交換格式,JSON 能夠將 JavaScript 對象中表示的一組數據轉換爲字符串,而後就能夠在函數之間輕鬆地傳遞這個字符串,或者在異步應用程序中將字符串從 Web 客戶機傳遞給服務器端程序。JSON和動態類型語言(如JavaScript)一塊兒使用時很是方便。然而在靜態類型語言中序列化數據時,JSON不但具備運行效率低的明顯缺點,並且會讓你寫更多的代碼來訪問數據。github
首先來看一下FlatBuffers項目爲開發者提供了哪些內容,能夠從官網下載源碼,其目錄結構以下圖: json
若是要將FlatBuffers 用到咱們的項目中,又須要哪些流程呢?能夠參考下面的流程圖:就像Parcel和Serializable的序列化同樣,FlatBuffers的是使用方式上也比最傳統的JSON序列化要複雜的多。在實際上面開發中,爲了下降開發的難度,提升開發效率,咱們會將源碼編譯成可植入的第三方庫。下面以Java環境爲例,來介紹FlatBuffers的簡單使用方法。讀者能夠到對應的maven倉庫下載。緩存
如今,假如咱們拿到的json文件的格式是下面這樣的:bash
{
"repos": [
{
"id": 27149168,
"name": "acai",
"full_name": "google/acai",
"owner": {
"login": "google",
"id": 1342004,
...
"type": "Organization",
"site_admin": false
},
"private": false,
"html_url": "https://github.com/google/acai",
"description": "Testing library for JUnit4 and Guice.",
...
"watchers": 21,
"default_branch": "master"
},
...
]
}
複製代碼
注:能夠經過下面的連接來獲取更完整的json對象服務器
咱們須要準備一個model文件,它定義了咱們想要序列化/反序列化 的數據結構,這個模式將被flatc用於建立Java模型以及從JSON到FlatBuffer二進制文件的轉換。網絡
如今,咱們所要作的全部事情就是建立3個表:ReposList,Repo和User,並定義root_type。例如:數據結構
table ReposList {
repos : [Repo];
}
table Repo {
id : long;
name : string;
full_name : string;
owner : User;
//...
labels_url : string (deprecated);
releases_url : string (deprecated);
}
table User {
login : string;
id : long;
avatar_url : string;
gravatar_id : string;
//...
site_admin : bool;
}
root_type ReposList;
複製代碼
注:完整的模式文件能夠點擊下面的連接來獲取
接下來,咱們所須要作的就是將repos_json.json轉換爲FlatBuffers二進制文件,併產生Java模型,其能夠以Java友好的方式表示咱們的數據,下面是轉換的命令:
$ ./flatc -j -b repos_schema.fbs repos_json.json
複製代碼
若是沒有任何報錯,將會生成以下4個文件:
repos_json.bin (將被重命名爲repos_flat.bin)
Repos/Repo.java
Repos/ReposList.java
Repos/User.java
複製代碼
接下來,咱們可使用FlatBuffers提供的Java庫來處理在Java中直接處理這種數據格式,此處使用須要使用到 flatbuffers-java-1.2.0-SNAPSHOT.jar。
public class MainActivity extends AppCompatActivity {
@Bind(R.id.tvFlat)
TextView tvFlat;
@Bind(R.id.tvJson)
TextView tvJson;
private RawDataReader rawDataReader;
private ReposListJson reposListJson;
private ReposList reposListFlat;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
rawDataReader = new RawDataReader(this);
}
@OnClick(R.id.btnJson)
public void onJsonClick() {
rawDataReader.loadJsonString(R.raw.repos_json).subscribe(new SimpleObserver<String>() {
@Override
public void onNext(String reposStr) {
parseReposListJson(reposStr);
}
});
}
private void parseReposListJson(String reposStr) {
long startTime = System.currentTimeMillis();
reposListJson = new Gson().fromJson(reposStr, ReposListJson.class);
for (int i = 0; i < reposListJson.repos.size(); i++) {
RepoJson repo = reposListJson.repos.get(i);
Log.d("FlatBuffers", "Repo #" + i + ", id: " + repo.id);
}
long endTime = System.currentTimeMillis() - startTime;
tvJson.setText("Elements: " + reposListJson.repos.size() + ": load time: " + endTime + "ms");
}
@OnClick(R.id.btnFlatBuffers)
public void onFlatBuffersClick() {
rawDataReader.loadBytes(R.raw.repos_flat).subscribe(new SimpleObserver<byte[]>() {
@Override
public void onNext(byte[] bytes) {
loadFlatBuffer(bytes);
}
});
}
private void loadFlatBuffer(byte[] bytes) {
long startTime = System.currentTimeMillis();
ByteBuffer bb = ByteBuffer.wrap(bytes);
reposListFlat = frogermcs.io.flatbuffs.model.flat.ReposList.getRootAsReposList(bb);
for (int i = 0; i < reposListFlat.reposLength(); i++) {
Repo repos = reposListFlat.repos(i);
Log.d("FlatBuffers", "Repo #" + i + ", id: " + repos.id());
}
long endTime = System.currentTimeMillis() - startTime;
tvFlat.setText("Elements: " + reposListFlat.reposLength() + ": load time: " + endTime + "ms");
}
}
複製代碼
在上面的示例代碼中,有兩個方法是比較核心的,須要咱們注意。
下面咱們來測試下FlatBuffers和傳統的json在數據解析上的耗時,咱們以4mb的JSON文件爲例。
如圖,能夠發現FlatBuffers花了1-5ms,JSON花了大約2000ms。而且FlatBuffers期間Android App中沒有GC,而在使用JSON時發生了不少次GC,測試的源碼能夠經過如下地址下載: FlatBuffers耗時測試