• protobuf lib库的使用


    问题记录:

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

    1 google::protobuf::compiler::DiskSourceTree sourceTree;
    2 sourceTree.MapPath("data", "./data");
    3 sourceTree.MapPath("", "D:\Documents\Program\Tools\protobuf-3.0.2\install\x86\debug\include");
    4 google::protobuf::compiler::Importer importer(&sourceTree, NULL);
    5 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的头文件和源代码进行了合并,最终合并成了三个文件:

      distjsonjson.h  distjsonjson-forwards.h  distjsoncpp.cpp

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

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

      1 #include <iostream>
      2 #include <google/protobuf/compiler/importer.h>
      3 #include <google/protobuf/dynamic_message.h>
      4 #include <google/protobuf/util/json_util.h>
      5 
      6 int parseProtoFile()
      7 {
      8     // 准备配置好文件系统
      9     google::protobuf::compiler::DiskSourceTree sourceTree;
     10     // 将当前路径映射为项目根目录 , project_root 仅仅是个名字,你可以你想要的合法名字.
     11     sourceTree.MapPath("data", "./data");
     12     sourceTree.MapPath("", "D:\Documents\Tools\protobuf-3.0.2\install\x86\debug\include");
     13     // 配置动态编译器.
     14     google::protobuf::compiler::Importer importer(&sourceTree, NULL);
     15     // 动态编译proto源文件。 源文件在./source/proto/test.proto .
     16     auto fileDescriptor = importer.Import("data/complex.proto");
     17 
     18 
     19     std::cout << fileDescriptor->message_type_count() << std::endl;
     20     for (auto i = 0; i < fileDescriptor->message_type_count(); i++)
     21     {
     22         auto descriptor = fileDescriptor->message_type(i);
     23         
     24         std::cout << descriptor->name() << " " << descriptor->field_count() << " " << descriptor->nested_type_count() << std::endl;
     25 
     26         auto descriptor1 = descriptor->containing_type();
     27 
     28         if (descriptor1)
     29         {
     30             std::cout << descriptor1->name() << std::endl;
     31         }
     32     }
     33     
     34     std::cout << fileDescriptor->name() << std::endl;
     35     
     36 
     37     auto descriptor = fileDescriptor->message_type(1);
     38     for (auto i = 0; i < descriptor->field_count(); i++)
     39     {
     40         auto fieldDes = descriptor->field(i);
     41         google::protobuf::SourceLocation outLocation;
     42         if (fieldDes->GetSourceLocation(&outLocation))
     43         {
     44             printf("%s: %d %d %d %d
    leading_comments:%s
    trailing_comments:%s
    ", 
     45                 fieldDes->full_name().c_str(),
     46                 outLocation.start_line, outLocation.start_column, outLocation.end_line, outLocation.end_column, 
     47                 outLocation.leading_comments.c_str(), outLocation.trailing_comments.c_str());
     48             for (auto comment : outLocation.leading_detached_comments)
     49             {
     50                 printf("leading_detached_comments:%s
    ", comment.c_str());
     51             }
     52         }
     53         else
     54         {
     55             std::cout << "fail" << std::endl;
     56         }
     57     }
     58     
     59 #if 0
     60     // 现在可以从编译器中提取类型的描述信息.
     61     auto descriptor1 = importer.pool()->FindMessageTypeByName("T.Test.InMsg");
     62     
     63     // 创建一个动态的消息工厂.
     64     google::protobuf::DynamicMessageFactory factory;
     65     // 从消息工厂中创建出一个类型原型.
     66     auto proto1 = factory.GetPrototype(descriptor1);
     67     // 构造一个可用的消息.
     68     auto message1 = proto1->New();
     69     // 下面是通过反射接口给字段赋值.
     70     auto reflection1 = message1->GetReflection();
     71     auto filed1 = descriptor1->FindFieldByName("id");
     72     reflection1->SetUInt32(message1, filed1, 1);
     73 
     74     // 打印看看
     75     std::cout << message1->DebugString() << std::endl;
     76 
     77     std::string output;
     78     google::protobuf::util::MessageToJsonString(*message1, &output);
     79     std::cout << output << std::endl;
     80 
     81     // 删除消息.
     82     delete message1;
     83 #endif
     84     return 0;
     85 }
     86 
     87 #define Log(format, ...) printf(format, __VA_ARGS__)
     88 
     89 void printOneField(const google::protobuf::FieldDescriptor *fieldDescriptor)
     90 {
     91     Log("  field[%d]: name %s, full name %s, json name %s, type %s, cpp type %s
    ",
     92         fieldDescriptor->index(), fieldDescriptor->name().c_str(), fieldDescriptor->full_name().c_str(), fieldDescriptor->json_name().c_str(),
     93         fieldDescriptor->type_name(), fieldDescriptor->cpp_type_name());
     94     Log("  debug string:%s
    ", fieldDescriptor->DebugString().c_str());
     95 }
     96 
     97 void printOneMessage(const google::protobuf::Descriptor *descriptor)
     98 {
     99     // 消息的总体信息
    100     Log("msg[%d]: name %s, full name %s, field count %d, nested type count %d
    ",
    101         descriptor->index(), descriptor->name().c_str(), descriptor->full_name().c_str(), descriptor->field_count(),
    102         descriptor->nested_type_count());
    103     Log("	debug string: %s
    ", descriptor->DebugString().c_str());
    104 
    105     // 遍历消息的所有字段
    106     for (int fieldLoop = 0; fieldLoop < descriptor->field_count(); fieldLoop++)
    107     {
    108         const google::protobuf::FieldDescriptor *fieldDescriptor = descriptor->field(fieldLoop);
    109 
    110         printOneField(fieldDescriptor);
    111     }
    112 
    113     // 遍历消息的所有嵌套消息
    114     for (int nestedLoop = 0; nestedLoop < descriptor->nested_type_count(); nestedLoop++)
    115     {
    116         const google::protobuf::Descriptor *nestedDescriptor = descriptor->nested_type(nestedLoop);
    117 
    118         printOneMessage(nestedDescriptor);
    119     }
    120 }
    121 
    122 void printOneFile(const google::protobuf::FileDescriptor *fileDescriptor)
    123 {
    124     Log("******** message info in proto file, msg count %d ********
    ", fileDescriptor->message_type_count());
    125 
    126     // 遍历文件中的所有顶层消息
    127     for (int msgLoop = 0; msgLoop < fileDescriptor->message_type_count(); msgLoop++)
    128     {
    129         const google::protobuf::Descriptor *descriptor = fileDescriptor->message_type(msgLoop);
    130 
    131         printOneMessage(descriptor);
    132     }
    133 }
    134 
    135 bool testProto(const char *protoIncludePath, const char *testProtoPath, const char *testProtoFile)
    136 {
    137     // 配置文件系统
    138     google::protobuf::compiler::DiskSourceTree sourceTree;
    139     sourceTree.MapPath("", protoIncludePath);
    140     sourceTree.MapPath("data", testProtoPath);
    141     //sourceTree.MapPath("data", "./data");
    142     //sourceTree.MapPath("", "D:\Documents\Tools\protobuf-3.0.2\install\x86\debug\include");
    143     // 配置动态编译器
    144     google::protobuf::compiler::Importer importer(&sourceTree, NULL);
    145     // 动态编译proto源文件
    146     const google::protobuf::FileDescriptor *fileDescriptor = importer.Import("data/" + std::string(testProtoFile));
    147 
    148     if (fileDescriptor == NULL)
    149     {
    150         printf("import "%s" failed, last error msg: %s
    ", testProtoFile, sourceTree.GetLastErrorMessage().c_str());
    151         return false;
    152     }
    153 
    154     printOneFile(fileDescriptor);
    155 
    156     return true;
    157 }
    158 
    159 int main()
    160 {
    161     const char *protoIncludePath = "D:\Documents\Tools\protobuf-3.0.2\install\x86\debug\include";
    162     const char *testProtoPath = "C:\Users\Administrator\Desktop\Document\C++\protobufTest\protobufTest\data";
    163     const char *testProtoFile = "complex.proto";
    164 
    165     testProto(protoIncludePath, testProtoPath, testProtoFile);
    166 
    167     //parseProtoFile();
    168     //printf("Hello world!
    ");
    169     return 0;
    170 }
  • 相关阅读:
    Android 6.0权限
    从最简单的HelloWorld理解MVP模式
    DataSet、DataTable和DataGridView知识备忘
    Windows 窗体启动和关闭的事件顺序
    VB二进制文件读写
    C#操作符的重载
    虚方法(virtual)和抽象方法(abstract)的区别
    我的前端页面开发js简易有效环境
    css properties
    css属性值语法解读
  • 原文地址:https://www.cnblogs.com/rmthy/p/8475922.html
Copyright © 2020-2023  润新知