Protobuf

作者: Qinginging | 来源:发表于2018-12-28 14:58 被阅读0次

    # Part 1: Protobuf Intro

    protobuf documentation详细介绍了关于protobuf的基本概念和初步使用法。
    Protobuf是Google开源的一种可用于结构化数据串行化(序列化)的数据缓存格式,适用于数据存储以及RPC数据交换格式。Protobuf将一个文件结构化为多个message组合而成。
    就我理解,好处有:

    1. 方便的序列化方式。提供了简单明了的接口来对自己定义好的结构化数据进行序列化和反序列化。
    2. 适合数据保密。若没有用户定义好的.proto格式,但看序列化到硬盘的文件很难知晓数据内容。
    3. 跨语言,定义一个.proto格式,再任何语言下均可以使用,使用提供的不同语言的wrapper即可。

    # Part 2: Protobuf Installaiton in MacOS

    官网下载protobuf,此时的最新版本是 3.6.1
    解压下载的文件并进入该目录

    ./configure
    make
    make check
    sudo make install
    

    顺利安装后,使用which protocprotoc --version来查看proto版本。

    # Part 3: Protobuf Definition

    先看一个例子

    syntax = "proto3"
    
    package tutorial;
    
    message Person {
      required string name = 1;
      required int32 id = 2;
      optional string email = 3;
     
      enum PhoneType{
          MOBILE = 0;
          HOME = 1;
          WORK = 2;
      }
    
     message PhoneNumber {
         required string number = 1;
         optional PhoneType type = 2 [default = HOME];
      }
    
      repeated PhoneNumber phones = 4;
    }
    
    message AddressBook {
      repeated Person people = 1;
    }
    

    开头是package的声明,用于防止不同工程下的重命名。

    protobuf 自动生成了一系列成员函数以便对信息内数据进行访问,以上面的Person为例:

    // name
    inline bool has_name() const;
    inline void clear_name();
    inline const ::std::string& name() const;
    inline void set_name(const ::std::string& value);
    inline void set_name(const char * value);
    inline ::std::string* mutable_name();
    
    // id
    inline bool has_id() const;
    inline void clear_id();
    inline int32_t id() const;
    inline void set_id(int32_t value);
    
    // email
    inline bool has_email() const;
    inline void clear_email();
    inline const ::std::string& email() const;
    inline void set_email(const ::std::string& value);
    inline void set_email(const char* value);
    inline ::std::string* mutable_email();
    
    // phones
    inline int phones_size() const;
    inline void clear_phones();
    inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const;
    inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones();
    inline const ::tutorial::Person_PhoneNumber& phones(int index) const;
    inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);
    inline ::tutorial::Person_PhoneNumber* add_phones();
    

    有以下几类函数:
    getters in lowercase : 和变量名字相同的函数名称。
    setters in highercase: 在变量名字前加上set_。
    clear: 用于将变量多置为空态。
    除此之外,还有一系列mutable_函数,能够得到指向变量的指针。从而进行set或者get操作。mutable调用时,所有的变量会自动设置为空。
    Repeated类型的信息域具有一些特殊的方法,如:
    1)size
    2)通过index 访问第几个元素
    3)通过add
    函数增加新的元素,此时也能返回该元素的指针

    # Part 4: Protobuf in Bazel

    WORKSPACE file:

    http_archive(
        name = "com_google_protobuf",
        urls = [
            "https://mirror.bazel.build/github.com/google/protobuf/archive/v3.6.1.tar.gz",
            "https://github.com/google/protobuf/archive/v3.6.1.tar.gz",
          ],
        sha256 = "3d4e589d81b2006ca603c1ab712c9715a76227293032d05b26fca603f90b3f5b",
        strip_prefix = "protobuf-3.6.1",
    )
    

    BUILD file:

    proto_library(
        name = "person_proto",
        srcs = ["Person.proto"],
    )
    
    # The cc_proto_library rule generates C++ code for a proto_library rule. It
    # must have exactly one proto_library dependency. If you want to use multiple
    # proto_library targets, create a separate cc_proto_library target for each
    # of them.
    #
    # Remote repository "com_google_protobuf_cc" must be defined to use this rule.
    cc_proto_library(
        name = "person_cc_proto",
        deps = [":person_proto"],
    )
    

    依赖关系需要按照:同目录,同工程,外部第三方的顺序

    # Part 5: Protobuf with zlib

    zlib是一个开源的压缩库,实现的deflate压缩算法,也是该库唯一实现的压缩算法。
    Que's C++ Studio关于理解和使用zlib库很详细。
    对.proto格式的数据字段进行压缩用到的是GZIP
    一个简单的例子如下:

    ...
    #include "scene.pb.h"
    
    #include <google/protobuf/io/zero_copy_stream_impl.h>
    #include <google/protobuf/io/gzip_stream.h>
    ...
    unsigned int const _COMPRESSION_LEVEL = 9;
    using namespace google::protobuf::io;
    
    int main() {
        GOOGLE_PROTOBUF_VERIFY_VERSION;
        
        Recipe::Scene * scene = new Recipe::Scene();
        
        /*
          initialization date in scene
        */
        
        std::ofstream output("scene.art", std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
        OstreamOutputStream outputFileStream(&output);
        
        GzipOutputStream::Options options;
        options.format = GzipOutputStream::GZIP;
        options.compression_level = _COMPRESSION_LEVEL;
    
        GzipOutputStream gzipOutputStream(&outputFileStream, &options);
        if (!scene->SerializeToZeroCopyStream(&gzipOutputStream))
        {
            std::cerr << "Failed to write scene." << std::endl;
            return -1;
        }
        Recipe::Scene * scene1 = new Recipe::Scene();
        {
            std::ifstream input("scene.art", std::ifstream::in | std::ifstream::binary);
            IstreamInputStream inputFileStream(&input);
            GzipInputStream GzipInputStream(&inputFileStream);
            if (!scene1->ParseFromZeroCopyStream(&GzipInputStream))
            {
                  std::cerr << "Failed to read scene." << std::endl;
                  return -1;
        }
        }
        std::cout << "scene1->imageData_size() " << scene1->imageData_size() << std::endl;
        google::protobuf::ShutdownProtobufLibrary();
        return 0;
    }
    

    即直接将.proto数据在序列化的同时进行压缩,对应的,在反序列时也是直接parse即可。

    out: ofstream --> OstreamOutputStream --> GZipOutputStream
    in: ifstream --> IstreamInputStream --> GZipInputStream
    

    相关文章

      网友评论

          本文标题:Protobuf

          本文链接:https://www.haomeiwen.com/subject/hunakqtx.html