protobuf lib库的使用

2018-02-26 来源: Jinglelove 发布在  http://www.cnblogs.com/rmthy/p/8475922.html

问题记录:

1、在使用protobuf反射机制动态加载解析proto文件时,发现当proto文件中含有import系统proto文件的语句时,无法解析文件,解决方法是添加路径映射。

 google::protobuf::compiler::DiskSourceTree sourceTree;
 sourceTree.MapPath("data", "./data");
 sourceTree.MapPath("", "D:\\Documents\\Program\\Tools\\protobuf-3.0.2\\install\\x86\\debug\\include");
 google::protobuf::compiler::Importer importer(&sourceTree, NULL);
 const google::protobuf::FileDescriptor *fileDescriptor = importer.Import("data/test.proto");

  代码如上,其中的第3行为解决方案,增加之后才能正确解析。分析其原因是,Importer对象用于导入并解析proto文件,当proto文件中import了其他proto文件时,Importer对象递归导入并解析该proto文件;第二行告诉了Importer去哪里找test.proto,但是却没有告诉Importer去哪里找系统自带的proto文件,因此需要加上第3行,并且别名应该留空!

2、jsoncpp的下载和使用

  jsoncpp源码可以从github上得到:jsoncpp-master.zip

  解压后使用python执行根目录下的 amalgamate.py ,这个脚本将jsoncpp的头文件和源代码进行了合并,最终合并成了三个文件:

  dist\json\json.h  dist\json\json-forwards.h  dist\jsoncpp.cpp

  使用时把 jsoncpp.cpp文件连同json文件夹一起拷贝到工程目录下,两者保持同级,代码中包含 json\json.h 即可。

3、遍历proto文件中的所有消息以及所有字段

 #include <iostream>
 #include <google/protobuf/compiler/importer.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/util/json_util.h>

 int parseProtoFile()
 {
     // 准备配置好文件系统
     google::protobuf::compiler::DiskSourceTree sourceTree;
     // 将当前路径映射为项目根目录 , project_root 仅仅是个名字,你可以你想要的合法名字.
     sourceTree.MapPath("data", "./data");
     sourceTree.MapPath("", "D:\\Documents\\Tools\\protobuf-3.0.2\\install\\x86\\debug\\include");
     // 配置动态编译器.
     google::protobuf::compiler::Importer importer(&sourceTree, NULL);
     // 动态编译proto源文件。 源文件在./source/proto/test.proto .
     auto fileDescriptor = importer.Import("data/complex.proto");

     std::cout << fileDescriptor->message_type_count() << std::endl;
     ; i < fileDescriptor->message_type_count(); i++)
     {
         auto descriptor = fileDescriptor->message_type(i);

         std::cout << descriptor->name() << " " << descriptor->field_count() << " " << descriptor->nested_type_count() << std::endl;

         auto descriptor1 = descriptor->containing_type();

         if (descriptor1)
         {
             std::cout << descriptor1->name() << std::endl;
         }
     }

     std::cout << fileDescriptor->name() << std::endl;

     auto descriptor = fileDescriptor->message_type();
     ; i < descriptor->field_count(); i++)
     {
         auto fieldDes = descriptor->field(i);
         google::protobuf::SourceLocation outLocation;
         if (fieldDes->GetSourceLocation(&outLocation))
         {
             printf("%s: %d %d %d %d\nleading_comments:%s\ntrailing_comments:%s\n",
                 fieldDes->full_name().c_str(),
                 outLocation.start_line, outLocation.start_column, outLocation.end_line, outLocation.end_column,
                 outLocation.leading_comments.c_str(), outLocation.trailing_comments.c_str());
             for (auto comment : outLocation.leading_detached_comments)
             {
                 printf("leading_detached_comments:%s\n", comment.c_str());
             }
         }
         else
         {
             std::cout << "fail" << std::endl;
         }
     }

 #if 0
     // 现在可以从编译器中提取类型的描述信息.
     auto descriptor1 = importer.pool()->FindMessageTypeByName("T.Test.InMsg");

     // 创建一个动态的消息工厂.
     google::protobuf::DynamicMessageFactory factory;
     // 从消息工厂中创建出一个类型原型.
     auto proto1 = factory.GetPrototype(descriptor1);
     // 构造一个可用的消息.
     auto message1 = proto1->New();
     // 下面是通过反射接口给字段赋值.
     auto reflection1 = message1->GetReflection();
     auto filed1 = descriptor1->FindFieldByName("id");
     reflection1->SetUInt32(message1, filed1, );

     // 打印看看
     std::cout << message1->DebugString() << std::endl;

     std::string output;
     google::protobuf::util::MessageToJsonString(*message1, &output);
     std::cout << output << std::endl;

     // 删除消息.
     delete message1;
 #endif
     ;
 }

 #define Log(format, ...) printf(format, __VA_ARGS__)

 void printOneField(const google::protobuf::FieldDescriptor *fieldDescriptor)
 {
     Log("  field[%d]: name %s, full name %s, json name %s, type %s, cpp type %s\n",
         fieldDescriptor->index(), fieldDescriptor->name().c_str(), fieldDescriptor->full_name().c_str(), fieldDescriptor->json_name().c_str(),
         fieldDescriptor->type_name(), fieldDescriptor->cpp_type_name());
     Log("  debug string:%s\n", fieldDescriptor->DebugString().c_str());
 }

 void printOneMessage(const google::protobuf::Descriptor *descriptor)
 {
     // 消息的总体信息
     Log("msg[%d]: name %s, full name %s, field count %d, nested type count %d\n",
         descriptor->index(), descriptor->name().c_str(), descriptor->full_name().c_str(), descriptor->field_count(),
         descriptor->nested_type_count());
     Log("\tdebug string: %s\n", descriptor->DebugString().c_str());

     // 遍历消息的所有字段
     ; fieldLoop < descriptor->field_count(); fieldLoop++)
     {
         const google::protobuf::FieldDescriptor *fieldDescriptor = descriptor->field(fieldLoop);

         printOneField(fieldDescriptor);
     }

     // 遍历消息的所有嵌套消息
     ; nestedLoop < descriptor->nested_type_count(); nestedLoop++)
     {
         const google::protobuf::Descriptor *nestedDescriptor = descriptor->nested_type(nestedLoop);

         printOneMessage(nestedDescriptor);
     }
 }

 void printOneFile(const google::protobuf::FileDescriptor *fileDescriptor)
 {
     Log("******** message info in proto file, msg count %d ********\n", fileDescriptor->message_type_count());

     // 遍历文件中的所有顶层消息
     ; msgLoop < fileDescriptor->message_type_count(); msgLoop++)
     {
         const google::protobuf::Descriptor *descriptor = fileDescriptor->message_type(msgLoop);

         printOneMessage(descriptor);
     }
 }

 bool testProto(const char *protoIncludePath, const char *testProtoPath, const char *testProtoFile)
 {
     // 配置文件系统
     google::protobuf::compiler::DiskSourceTree sourceTree;
     sourceTree.MapPath("", protoIncludePath);
     sourceTree.MapPath("data", testProtoPath);
     //sourceTree.MapPath("data", "./data");
     //sourceTree.MapPath("", "D:\\Documents\\Tools\\protobuf-3.0.2\\install\\x86\\debug\\include");
     // 配置动态编译器
     google::protobuf::compiler::Importer importer(&sourceTree, NULL);
     // 动态编译proto源文件
     const google::protobuf::FileDescriptor *fileDescriptor = importer.Import("data/" + std::string(testProtoFile));

     if (fileDescriptor == NULL)
     {
         printf("import \"%s\" failed, last error msg: %s\n", testProtoFile, sourceTree.GetLastErrorMessage().c_str());
         return false;
     }

     printOneFile(fileDescriptor);

     return true;
 }

 int main()
 {
     const char *protoIncludePath = "D:\\Documents\\Tools\\protobuf-3.0.2\\install\\x86\\debug\\include";
     const char *testProtoPath = "C:\\Users\\Administrator\\Desktop\\Document\\C++\\protobufTest\\protobufTest\\data";
     const char *testProtoFile = "complex.proto";

     testProto(protoIncludePath, testProtoPath, testProtoFile);

     //parseProtoFile();
     //printf("Hello world!\n");
     ;
 }

相关文章