一 基本說(shuō)明
.proto文件使用基本說(shuō)明
結(jié)構(gòu)定義文件為.proto
敬察,可以使用import
包含另一個(gè).proto
文件,注釋使用//
二 語(yǔ)法
1 字段限制
required
: 必須賦值的字符
optional
: 可有可無(wú)的字段蹂安,可以使用[default = xxx]配置默認(rèn)值
repeated
: 可重復(fù)變長(zhǎng)字段锐帜,類(lèi)似數(shù)組
2 tag
每個(gè)字段都有獨(dú)一無(wú)二的tag
tag 1-15是字節(jié)編碼,16-2047使用2字節(jié)編碼缠黍,所以1-15給頻繁使用的字段
3 類(lèi)型
系統(tǒng)默認(rèn)值:
string默認(rèn)為空字符串瓷式;
bool默認(rèn)為false语泽;
數(shù)值默認(rèn)為0;
enum默認(rèn)為第一個(gè)元素
4 解析與序列化
每個(gè)message都包含如下方法廊驼,用于解析和序列化惋砂,注意目標(biāo)是字節(jié)形式,非文本酝掩。
bool SerializeToString(string* output) const
: 將message序列化成二進(jìn)制保存在output中眷柔,注意保存的是二進(jìn)制,不是文本镶苞;僅僅是string作為容器鞠评。
bool ParseFromString(const string& data)
: 從給定的二進(jìn)制數(shù)值中解析成message
bool SerializeToOstream(ostream* output) const
: 序列化到ostream中
bool ParseFromIstream(istream* input)
: 從istream中解析出message
三 舉例介紹
1 建立.proto文件
建立.proto
文件定義message
,如下addressbook.proto
:
syntax = "proto2"; // 定義語(yǔ)法類(lèi)型煌贴,通常proto3好于proto2,proto2好于proto1
package tutorial; // 定義作用域
message Person { // 生成類(lèi)class Person : public ::google::protobuf::Message
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType { // 定義枚舉類(lèi)型怠肋,生成Person_PhoneType類(lèi)型
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber { // 生成Person_PhoneNumber類(lèi)
required string number = 1;
optional PhoneType type = 2 [default = HOME]; // 值必須是枚舉類(lèi)型中的一個(gè)
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
2 生成源文件
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
其中protoc工具地址:protoc
1) message Person{}
會(huì)生成源碼如下:
class Person : public ::google::protobuf::Message {
Person(); // 默認(rèn)構(gòu)造函數(shù)
~Person(); // 默認(rèn)析構(gòu)函數(shù)
Person(const Person& other); // 拷貝構(gòu)造函數(shù)
Person& operator=(const Person& other); // 賦值構(gòu)造函數(shù)
void Swap(Person* other); // 內(nèi)容交換
const UnknownFieldSet& unknown_fields() const;
UnknownFieldSet* mutable_unknown_fields();
static const Descriptor* descriptor();
static const Foo& default_instance();
};
2) required string name
生成源碼如下:
bool has_name() const; // 返回true笙各,如果name被設(shè)置
void clear_name(); // 清除name杈抢,has_name會(huì)返回false
const ::std::string& name() const; // 返回name字符串
void set_name(const ::std::string& value); // 設(shè)置name字符串
::std::string* mutable_name(); // 可以修改的字符串仑性,has_name會(huì)返回true
3) required int32 id
生成源碼如下:
bool has_id() const; // 返回true,如果id被設(shè)置
int32 id() const; // 返回id數(shù)值
void set_id(int32 value); // 設(shè)置id數(shù)值
void clear_id(); // 清除id歼捐,has_id會(huì)返回false
4) message Person { message PhoneNumber }
生成類(lèi)Person_PhoneNumber
晨汹,并在Person
類(lèi)內(nèi)定義:
typedef Person_PhoneNumber PhoneNumber;
其他消息如果要使用PhoneNumber
,使用方法如下:
message OtherPerson {
optional Person.PhoneNumber number = 1;
}
3 定義prototxt文件
定義如下:
people{
name : "Lucy"
id : 120
email : "lucy@163.com"
phones{
number : "13540737210"
type : HOME
}
}
4 代碼中解析prototxt文件
/*************************************************************************
> File Name: main.cpp
> Author: ma6174
> Mail: ma6174@163.com
> Created Time: Wed 09 Jan 2019 11:04:56 PM CST
************************************************************************/
#include<iostream>
#include "tutorial.AddressBook.pb.h"
using namespace std;
int main() {
tutorial::Person one;
string filename = "one.prototxt";
ReadProtoFromTextFileOrDie(filename, &one);
return 0;
}
編譯命令:
g++ main.cpp *.cc -std=c++11 `pkg-config --cflags --libs protobuf`
這一步編譯報(bào)錯(cuò):
main.cpp:15:43: error: ‘ReadProtoFromTextFileOrDie’ was not declared in this scope
ReadProtoFromTextFileOrDie(filename, &one);
^
需要進(jìn)一步學(xué)習(xí)...
參考
[1] 官方指南.Protocol Buffer Basics: C++
[2] 博客.序列化之protobuf