c ++ protobuf:如何迭代消息的字段?
我是protobuf的新手,我坚持简单的任务:我需要遍历消息的字段并检查它的类型。 如果类型是消息,我将对此消息递归地做同样的事情。
例如,我有这样的信息:
package MyTool;
message Configuration {
required GloablSettings globalSettings = 1;
optional string option1 = 2;
optional int32 option2 = 3;
optional bool option3 = 4;
}
message GloablSettings {
required bool option1 = 1;
required bool option2 = 2;
required bool option3 = 3;
}
现在,要明确地访问C ++中的字段值,我可以这样做:
MyTool::Configuration config;
fstream input("config", ios::in | ios::binary);
config.ParseFromIstream(&input);
bool option1val = config.globalSettings().option1();
bool option2val = config.globalSettings().option2();
等等。 这种方法在有大量字段的情况下不方便。
我可以通过迭代来完成此操作并获取字段的名称和类型吗? 我知道有些类型的描述符,有些被称为反射,但是我没有成功。 如果可能的话,有人能给我一个例子吗?
谢谢!
看看Protobuf库如何实现TextFormat::Printer
类,该类使用描述符和反射来迭代字段并将它们转换为文本:
https://github.com/google/protobuf/blob/master/src/google/protobuf/text_format.cc#L1473
这是旧的,但也许有人会受益。 这是一个打印protobuf消息内容的方法:
void Example::printMessageContents(std::shared_ptr<google::protobuf::Message> m)
{
const Descriptor *desc = m->GetDescriptor();
const Reflection *refl = m->GetReflection();
int fieldCount= desc->field_count();
fprintf(stderr, "The fullname of the message is %s n", desc->full_name().c_str());
for(int i=0;i<fieldCount;i++)
{
const FieldDescriptor *field = desc->field(i);
fprintf(stderr, "The name of the %i th element is %s and the type is %s n",i,field->name().c_str(),field->type_name());
}
}
你可以在FieldDescriptor Enum Values中找到你从field->type
得到的可能值。 例如,对于消息类型,您必须检查类型是否等于FieldDescriptor::TYPE_MESSAGE
。
该功能打印protobuf消息的所有“元数据”。 但是,您需要分别检查每个值的类型,然后使用反射调用相应的getter函数。
所以使用这个条件我们可以提取字符串:
if(field->type() == FieldDescriptor::TYPE_STRING && !field->is_repeated())
{
std::string g= refl->GetString(*m, field);
fprintf(stderr, "The value is %s ",g.c_str());
}
然而,字段可以重复或不重复,对于两种字段类型都使用不同的方法。 所以这里使用一张支票来确保我们使用正确的方法。 对于重复的字段,我们有例如这种字符串的方法:
GetRepeatedString(const Message & message, const FieldDescriptor * field, int index
)
因此需要考虑重复字段的索引。
对于类型为Message的FieldDescriptor,所提供的功能只会打印邮件的名称,我们最好打印其内容。
if(field->type()==FieldDescriptor::TYPE_MESSAGE)
{
if(!field->is_repeated())
{
const Message &mfield = refl->GetMessage(*m, field);
Message *mcopy = mfield.New();
mcopy->CopyFrom(mfield);
void *ptr = new std::shared_ptr<Message>(mcopy);
std::shared_ptr<Message> *m =
static_cast<std::shared_ptr<Message> *>(ptr);
printMessageContents(*m);
}
}
最后,如果字段重复,则必须在反射上调用FieldSize
方法并迭代所有重复的字段。
上一篇: c++ protobuf: how to iterate through fields of message?