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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM