轉載請注明出處:
http://www.cnblogs.com/darkknightzh/p/5804395.html
參考網址:
http://www.cnblogs.com/luosongchao/p/3969988.html
1. 在當前文件夾內新建addressbook.proto,並輸入:
package ContactInfo; message Person { required string curName = 1; required int32 curId = 2; optional string curEmail = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 4; optional PhoneType type = 2[default = HOME]; } repeated PhoneNumber phone = 4; } message AddressBook { required string owner = 10; repeated Person personInfo = 6; }
2. 將終端定位到當前文件夾,並輸入:
protoc --cpp_out=./ addressbook.proto
說明:a 如果希望生成的.h和.cpp都在當前文件夾,則--cpp_out=./即可。
b 如果使用如下命令:
protoc -I=src --cpp_out=dst src/ addressbook.proto
則addressbook.proto在當前文件夾的src文件夾里,生成的.h和.cpp均位於當前文件夾下的dst文件夾下面。
c 生成的頭文件中,ContactInfo為命名空間,里面包含Person、PhoneNumber、AddressBook三個類。枚舉類型則看該類型所在的類,使用作用域限定符來訪問,如:
ContactInfo::Person::MOBILE
3. 在生成的.h和.cpp文件所在的文件夾內,新建testAddBook.cpp,並輸入:

1 #include "addressbook.pb.h" 2 #include <fstream> 3 #include <iostream> 4 using namespace std; 5 6 ///////////////////////////////////////////////////////////////////////////////// 7 int saveAddInfo() 8 { 9 ContactInfo::AddressBook addbook; 10 addbook.set_owner("xxx"); 11 12 // first person 13 ContactInfo::Person* pperson = addbook.add_personinfo(); 14 pperson->set_curname("aaa"); 15 pperson->set_curid(25); 16 pperson->set_curemail("aaa@126.com"); 17 18 ContactInfo::Person_PhoneNumber* pPhoneNum = pperson->add_phone(); 19 pPhoneNum->set_number("111111111"); 20 pPhoneNum->set_type(ContactInfo::Person::HOME); 21 22 pPhoneNum = pperson->add_phone(); 23 pPhoneNum->set_number("222222222"); 24 pPhoneNum->set_type(ContactInfo::Person::MOBILE); 25 26 // second person 27 pperson = addbook.add_personinfo(); 28 pperson->set_curname("bbb"); 29 pperson->set_curid(30); 30 // pperson->set_curemail("bbb@126.com"); 31 32 pPhoneNum = pperson->add_phone(); 33 pPhoneNum->set_number("333333333"); 34 // pPhoneNum->set_type(ContactInfo::Person::HOME); 35 36 pPhoneNum = pperson->add_phone(); 37 pPhoneNum->set_number("444444444"); 38 pPhoneNum->set_type(ContactInfo::Person::MOBILE); 39 40 // int length = addbook.ByteSize(); 41 // char* buf = new char[length]; // serialize to char*, and transmit by net or others 42 // addbook.SerializeToArray(buf,length); 43 44 fstream output("pbinfo.log", ios::out|ios::trunc|ios::binary); 45 if(!addbook.SerializeToOstream(&output)) 46 { 47 cerr << "fail to write msg" << endl; 48 //delete[] buf; 49 return -1; 50 } 51 52 //delete[] buf; 53 return 0; 54 } 55 56 //////////////////////////////////////////////////////////////////////////// 57 void showMsg(const ContactInfo::AddressBook& addbook) 58 { 59 cout << addbook.owner() << endl; 60 for (int i = 0; i < addbook.personinfo_size(); ++i) 61 { 62 cout << addbook.personinfo(i).curname() << endl; 63 cout << addbook.personinfo(i).curid() << endl; 64 if(addbook.personinfo(i).has_curemail()) 65 cout << addbook.personinfo(i).curemail() << endl; 66 else 67 cout << "no email" << endl; 68 69 for (int j = 0; j < addbook.personinfo(i).phone_size(); ++j) 70 { 71 cout<<addbook.personinfo(i).phone(j).number() << endl; 72 if(addbook.personinfo(i).phone(j).has_type()) 73 cout << addbook.personinfo(i).phone(j).type() << endl; 74 else 75 cout << "no phone type" << endl; 76 } 77 } 78 } 79 80 void showMsgbyAuto(ContactInfo::AddressBook addbook) 81 { 82 cout << addbook.owner() << endl; 83 84 auto pperson = addbook.mutable_personinfo(); 85 for (auto it = pperson->begin(); it != pperson->end(); ++it) 86 { 87 cout << it->curname() << endl; 88 cout << it->curid() << endl; 89 if(it->has_curemail()) 90 cout << it->curemail() << endl; 91 else 92 cout << "no email" << endl; 93 94 auto pPhoneNum = it->mutable_phone(); 95 for (auto ij = pPhoneNum->begin(); ij != pPhoneNum->end(); ++ij) 96 { 97 cout << ij->number() << endl; 98 if(ij->has_type()) 99 cout << ij->type() << endl; 100 else 101 cout << "no phone type" << endl; 102 } 103 } 104 } 105 106 int loadAddInfo() 107 { 108 ContactInfo::AddressBook addbook; 109 110 fstream input("pbinfo.log", ios::in|ios::binary); 111 if(!addbook.ParseFromIstream(&input)) 112 { 113 cout << "fail to write msg" << endl; 114 return -1; 115 } 116 cout << "now show msg" << endl; 117 showMsg(addbook); 118 cout << endl; 119 showMsgbyAuto(addbook); 120 121 return 0; 122 } 123 124 /////////////////////////////////////////////////////////////////////////////// 125 int main() 126 { 127 int choice; 128 cout << "input choice: 1 for save, 2 for load" << endl; 129 cin >> choice; 130 if(1 == choice) 131 { 132 saveAddInfo(); 133 } 134 else if (2 == choice) 135 { 136 loadAddInfo(); 137 } 138 139 return 0; 140 }
說明:上面程序使用SerializeToArray后,可以將數據放到buf的緩沖區中,方便使用網絡或者其他方式發送。
4. 終端定位到testAddBook.cpp所在文件夾,並輸入:
g++ -std=c++11 addressbook.pb.cc testAddBook.cpp -o testAddBook -lprotobuf -pthread
說明:a 上面程序showMsgbyAuto函數使用了C++11特性,因而終端中需要加上-std=c++11;否則可以不加。如果不使用C++11特性,則使用下面的方式訪問,但是太長。。。:
::google::protobuf::RepeatedPtrField< ::ContactInfo::Person >
b 如果protobuf沒有安裝到/usr路徑,而是/usr/local路徑,可能需要下面的命令:
c 此處不能使用gcc編譯,我這里提示出錯了:
/usr/bin/ld: /tmp/ccO3HeHo.o: undefined reference to symbol '_ZNSaIcED1Ev@@GLIBCXX_3.4' //usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols: DSO missing from command line collect2: error: ld returned 1 exit status
===========================================================================
170122更新:
d 如果編譯該cpp文件的時候,提示好多未定義的引用:
addressbook.pb.cc:(.text+0x133):對‘google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(google::protobuf::Descriptor const*, google::protobuf::Message const*, int const*, int, int, int, int, int, int)’未定義的引用 addressbook.pb.cc:(.text+0x193):對‘google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(google::protobuf::Descriptor const*, google::protobuf::Message const*, int const*, int, int, int, int, int, int)’未定義的引用
可能是因為電腦安裝了兩個不同版本的protobuf(ubuntu16默認已經安裝了protobuf.so.9這系列的,新裝的是protobuf.so.10系列的)。默認的路徑見http://www.cnblogs.com/darkknightzh/p/5782992.html中160819更新。
170122更新結束
===========================================================================
5. 終端中輸入./testAddBook,之后輸入1,會存儲pbinfo.log文件。
6. 終端中輸入./testAddBook,之后輸入2,顯示如下:
說明解析的文件成功。
說明:對於optional可選項,可以不使用has_xxx()進行判斷,此時不輸出(程序有endl,所以會輸出一個空行)(不知道其他使用方式時,會是什么情況)。