zoukankan      html  css  js  c++  java
  • 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。

         

  • 相关阅读:
    flask1 + jinja2 day88
    linux9
    linux8 redis集群槽+docker
    dsadfa
    redis
    aaa
    a
    题目
    java对含有中文的字符串进行Unicode编码
    Java转Double类型经纬度为度分秒格式
  • 原文地址:https://www.cnblogs.com/relvin/p/5540063.html
Copyright © 2011-2022 走看看