c++對象的序列化與反序列化的解決方案----flatbuffers的使用


概述

  本篇blog主要是給大家介紹FlatBuffers的相關的信息和用法,當我在了解的FlatBuffers時,國內還沒有一些相關的文章去介紹FlatBuffers,不得不翻牆去google相關的用法,然后理解並應用到自己的代碼中,學習的時間成本很高。所以就花了點時間整理一份具體的用法,提供給大家一個參考。

簡介

一、什么是FlatBuffers?

  FlatBuffers是一個開源的、跨平台的、高效的、提供了C++/Java接口的序列化工具庫。它是Google專門為游戲開發或其他性能敏感的應用程序需求而創建。尤其更適用於移動平台,這些平台上內存大小及帶寬相比桌面系統都是受限的,而應用程序比如游戲又有更高的性能要求。它將序列化數據存儲在緩存中,這些數據既可以存儲在文件中,又可以通過網絡原樣傳輸,而不需要任何解析開銷。

代碼托管主頁: https://github.com/google/flatbuffers

項目介紹主頁: http://google.github.io/flatbuffers/index.html

 

二、FlatBuffers用途有哪些?

  1、對C++代碼的序列化與反序列化:①寫本地緩存,方便讀取。②用於網絡數據發送。

  2、將xml、json文件轉換成二進制文件,大大縮減加載文件時間

用法

 關於FlatBuffers的用法,我下面還是通過代碼向大家講解,這樣更直觀,更容易理解。

 

class Point
{
    float x;
    float y;
};

class Node
{

   std::string name;
   Point position;
};

class Layer
: public Node
{
   Node* friend;
   std::vector<Node*> children;
   std::vector<Point *> transform;
};

1、使用前的准備

  首先構建一個schema文件。schema文件主要是記錄了我們所要用的對象的成員信息。

 

//>>>>>>>>> schema begin <<<<<<<<<<<
namespace Layer; table Point_Fb { x:float;
  y:float;
} table Node_Fb { name:string;
  position:Point_Fb; }
table Layer_Fb
{
  super:Node_Fb;
  friend:Node_Fb;
  children:[Node_Fb];
  transform:[Point_Fb];
} root_type Layer_Fb;
//>>>>>>>>> schema end <<<<<<<<<<<
到這里我們的schema文件已經寫完了,然后保存為
Layer_Fb.fbs文件。
然后下載google的flatbuffers的開源代碼編譯flatc.cpp得到flatc可執行文件,然后運行
flatc -c -o ./ ./Layer_Fb.fbs 生成一個Layer_Fb_generated.h的頭文件,加到項目中。到這里,我們的准備工作就做完了。

注:

  1、flatbuffers的類型有很多我就沒有一一列舉了,大家可以在flatbuffers的文檔里看到。
  2、schema文件中的除了table還有struct。區別就在於able是Flatbuffers中用來定義對象的主要方式,和struct最大的區別在於:它的每個字段都是可選的,而struct的所有成員都是required。 
    table除了成員名稱和類型之外,還可以給成員一個默認值,如果不顯式指定,則默認為0(或空)。struct不能定義scalar成員,比如說string類型的成員。在生成C++代碼時,struct的成員順序
    會保持和IDL的定義順序一致,如果有必要對齊,生成器會自動生成用於對齊的額外成員。
    如果沒有Layer中沒有std::vector<Point*> tranform,那么這里我們的Point的定義可以是struct Point_Fb,因為我沒有找到flatbuffers里面如何使用結構體數組的方法。(如果各位有找到還望不吝賜教)

2、具體使用方法

    1、序列化

    這里我有個對象就是auto layer = new Layer();如何序列化呢?

    我們就是要創建一個layer_Fb的對象,這個就是Layer對象對應的flatbuffers的對象,他包含了Layer對象的所有的信息。

    

#include "Layer_Fb_generated.h"
    flatbuffers::FlatBufferBuilder builder_data;
    auto position_fb = CreatePoint_Fb(builder_data,layer.position.x,layer.position.y);
    auto super_fb = CreateNode_Fb(builder_data,builder_data.CreateString(layer.name),&position_fb);
    auto friend_fb = ...;
    
    std::vector<flatbuffers::Offset<Node_Fb>> Node_fbList;
    for (auto child : layer.children)
    {
        auto position_fb = CreatePoint_Fb(builder_data,child.position.x,child.position.y);
        auto child_fb = CreateNode_Fb(builder_data,builder_data.CreateString(child.name),&position_fb);
        Node_fbList.push_back(child_fb);
    }
    
    std::vector<flatbuffers::Offset<Point_Fb>> transformList;
    for (auto point : layer.transform)
    {
        auto position_fb = CreatePoint_Fb(builder_data,layer.position.x,position.y);
        transformList.push_back(position_fb);
    }
    
    auto layer_fb = CreateLayer_Fb(builder_data,position_fb,super_fb,friend_fb,Node_fbList,transformList);
//    auto layer_fb = CreateLayer_Fb(builder_data,
//                                   position_fb,
//                                   super_fb,
//                                   friend_fb,
//                                   Node_fbList.size() == 0 ? 0 : Node_fbList, //這樣可以減少多余存儲空間
//                                   transformList);
    builder_data.Finish(texture);
    
//    (char *)builder_data.GetBufferPointer(), builder_data.GetSize() 取得轉換后的二進制文件。保存到本地或者用於網絡傳輸

  2、反序列化

    

auto layer_fb = flatbuffers::GetRoot<Layer_Fb>(builder_data.GetBufferPointer());//
    layer_fb->super/*schema 中的對象的名字*/();
    layer_fb->friend();
    layer_fb->children();
    layer_fb->transfrom();
  創建layer對象,對其一個個賦值就可以了。

注:
  這里並不是只能對schame中的root_type才能序列化,例如:你想只對Node_fb進行序列化,你就可以在得到node_fb對象的時候直接builder.finish(node_fb),返回利用
  flatbuffers::GetRoot<Node_Fb/*類型不要錯咯*/>(builder_data.GetBufferPointer());方法一樣可以

 

3、擴展

  那么如何對xml、json文件進行序列化呢?

  我的做法就是把xml、json文件解析成c++對象,然后序列化,保存到本地。然后就用保存的文件進行讀取、反序列化操作。我對比過兩中方式的讀取效率。很明顯讀取flatbuffers文件后進行反序列化要比xml、json速度快6~10倍!但看這個值可能沒感覺,當你解析一個xml可能用0.01s,但是解析flatbuffers文件你只要0.003秒。文件一多對比就會出來了。尤其是在手機游戲上的時候,啟動和界面切換加載就會明顯快好多。(如果你從事cocos2dx開發的話,你可以研究研究cocos的csb文件,其實就是一個flatbuffers文件。)    

 

謝謝各位的閱讀!

各位有什么疑問可以直接在我的blog下留言或者是發送的我的個人郵箱relvin@qq.com。

 

 

     

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM