c++对象的序列化与反序列化的解决方案----flatbuffers的使用

概述

  本篇blog主要是给大家介绍FlatBuffers的相关的信息和用法,当我在了解的FlatBuffers时,国内还没有一些相关的文章去介绍FlatBuffers,不得不FQ去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。

 

 

     

 

posted @ 2016-05-29 18:57  Relvin  阅读(19856)  评论(0编辑  收藏  举报