protobuf使用

Protobuf C++的简单使用-带例程

Protobuf简介

以C++而言,简单的说就是可以将多种类型的数据如vector、map序列化至协议缓存区中,协议缓冲区的数据可以用来进程之间通信,也可以以二进制形式直接写到硬盘中,实现不占用内存的目的。Protobuf读写速度快,一般都在ms级别,是目前最高效的序列化工具。
protobuf由一些基础的消息类型组成更高级的数据类型,这里以一个包含Eigen的结构体在硬盘中的读写为例。

syntax = "proto3";

package proto;

message Vector3d {
  double x = 1;
  double y = 2;
  double z = 3;
}

message RangeData {
  repeated int32 point_x = 1;
  repeated int32 point_y = 2;
  Vector3d local_pose = 3;
  int64 time_stamp;
}

其中repeated声明了一个类似于std::vector的数据,可连续存储,以上消息在C++对应了一个结构体:

struct RangeData {
  RangeData();
  explicit RangeData(const proto::RangeData& range_data_proto);
  std::vector<double> points_x;
  std::vector<double> points_y;
  Eigen::Vector3d local_pose;
  int64_t time_stamp;
}; 

其中explicit RangeData(const proto::RangeData& range_data)输入参数为proto::RangeData,即是前面所定义的消息类型message RangeData,对于此结构体,我们需要写一个以proto作为输入的构造函数,和将当前数据输出为Proto的输出函数ToProto,两个函数实现如下:

// 基于proto的构造函数
Eigen::Vector3d ToEigen(const proto::Vector3d& proto) {
  return Eigen::Vector3d(proto.x(), proto.y(), proto.z());
}

RangeData::RangeData(const proto::RangeData& range_data_proto) {
  this->time_stamp = range_data_proto.time_stamp();
  this->local_pose = ToEigen(range_data_proto.local_pose());
  for(const auto& point_x : range_data_proto.points_x()) {
    this->points_x.emplace_back(point_x);
  }
  for(const auto& point_y : range_data_proto.points_y()) {
    this->points_y.emplace_back(point_y);
  }
}

// 将range_data输出为proto
proto::Vector3d ToProto(const Eigen::Vector3d& vector) {
  proto::Vector3d proto;
  proto.set_x(vector.x());
  proto.set_y(vector.y());
  proto.set_z(vector.z());
  return proto;
}

proto::RangeData ToProto(const RangeData& range_data) {
  proto::RangeData proto;
  *proto.mutable_points_x() = {range_data.points_x.begin(), range_data.points_x.end()};
  *proto.mutable_points_y() = {range_data.points_y.begin(), range_data.points_y.end()};
  *proto.mutable_local_pose() = ToProto(range_data.local_pose);
  proto.set_time_stamp(range_data.time_stamp);
  return proto;
}

以上就实现了基于proto的读写,得到了协议缓冲区数据proto::RangeData,进一步可以将此函数以二进制形式写到硬盘中,这部分是参考cartograpth代码,在本文例程的proto_io.h proto_io.cc中实现。

本文例程

protobuf需要安装google的protobuf库,安装参考
https://www.lmlphp.com/user/56/article/item/6067/

同时可以将protobuf用cmake生成动态.so库,需要的时候直接链接就好,本例程的Proto cmake:

# 查找 protobuf
find_package(Protobuf REQUIRED)

# 编译 proto 为 .cpp 和 .h
FILE(GLOB PROTO_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.proto")
message(STATUS ${PROTO_FILES})

PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTO_FILES})
message("PROTO_SRCS = ${PROTO_SRCS}")
message("PROTO_HDRS = ${PROTO_HDRS}")

add_library(proto STATIC ${PROTO_SRCS} ${PROTO_HDRS})

target_link_libraries(proto ${Protobuf_LIBRARIES}) 

target_include_directories(proto
        PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
        PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
        PUBLIC ${PROTOBUF_INCLUDE_DIRS})

在主程序中将其作为子模块,主程序的cmake:

cmake_minimum_required(VERSION 3.2)

project(proto_demo)

find_package(Eigen3 REQUIRED)
set(BOOST_COMPONENTS iostreams)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})

include_directories(include
										build # 为了更方便的使用proto的代码提示
                    ${EIGEN3_INCLUDE_DIR}
										${Boost_INCLUDE_DIRS})

add_subdirectory(proto)
add_library(${PROJECT_NAME} 
						src/grid_2d.cc 
            src/submap_2d.cc
						src/proto_io.cc
						)
target_link_libraries(${PROJECT_NAME} proto ${Boost_LIBRARIES})
add_executable(demo app/demo.cc)
target_link_libraries(demo ${PROJECT_NAME})

具体例程如下:

git clone https://github.com/hipforth/proto_demo.git
cd proto_demo && mkdir build && cd build
cmake .. && make
./demo demo.bin

demo.bin即为写入的protobuf二进制格式数据

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值