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

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。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
序列化是将对象转换成字节流的过程,而反序列化是将字节流转换回原始对象的过程。序列化反序列化在网络传输和存储数据中起到了重要的作用。 序列化的优点在于: 1. 数据传输:序列化后的字节流可以方便地在网络中传输,可以减少网络传输的时间和带宽消耗。 2. 数据存储:序列化后的字节流可以被持久化保存在磁盘中,方便后续读取和使用。 3. 跨平台交互:序列化后的字节流可以在不同的编程语言和操作系统间进行交互,实现跨平台的数据传输和共享。 然而,序列化也存在一些缺点,比如: 1. 复杂性:为每种对象类型定义专门的序列化反序列化方法相对复杂,需要额外的工作量和代码维护。 2. 可读性:序列化后的字节流通常是机器可读的,不易阅读和理解。 在实际应用中,根据具体需求和场景,可以选择不同的序列化方法。比如,在引用中提到了JSON序列化和专用序列化方法,JSON序列化具有较好的可读性,但序列化后占用的字节较多;而专用序列化方法虽然序列化后字节较少,但需要为每种对象类型定义专门的序列化反序列化方法。 总结起来,序列化是将对象转换成字节流的过程,而反序列化是将字节流转换回原始对象的过程。序列化的优点包括方便的数据传输和存储,以及跨平台交互的能力。然而,序列化也存在复杂性和可读性的问题。在实际应用中,需要根据需求选择合适的序列化方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值