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的头文件和源代码进行了合并,最终合并成了三个文件:

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

  使用时把 jsoncpp.cpp文件连同json文件夹一起拷贝到工程目录下,两者保持同级,代码中包含 json\json.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\nleading_comments:%s\ntrailing_comments:%s\n", 
 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\n", 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\n",
 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\n", 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\n",
101         descriptor->index(), descriptor->name().c_str(), descriptor->full_name().c_str(), descriptor->field_count(),
102         descriptor->nested_type_count());
103     Log("\tdebug string: %s\n", 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 ********\n", 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\n", 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!\n");
169     return 0;
170 }

 

posted on 2018-02-26 20:31  Jinglelove  阅读(5372)  评论(0编辑  收藏  举报