赞
踩
protocol buffers是谷歌的语言中立、平台中立、可扩展的结构化数据序列化机制——XML,但更小、更快、更简单。您可以一次定义数据的结构化方式,然后可以使用特殊生成的源代码轻松地使用各种语言(C++/ C#/ Dart/ Go/ Java/ Kotlin/ Python)在各种数据流中写入和读取结构化数据。
最简单的方式:
sudo apt install protobuf-compiler
如果你想使用指定版本,可到官网下载protobuf git官网,选择下载cpp的压缩包(如protobuf-cpp-3.19.1.zip),解压并用make编译(如果用make直接编译会找不到libprotoc.so。Error while loading shared libraries: libprotoc.so.xx: cannot open shared object file: No):
unzip protobuf-cpp-3.19.1.zip
cd protobuf-3.19.1
./configure
make
sudo make install
如果你想使用指定版本,可到官网下载protobuf git官网,选择下载cpp的压缩包(如protobuf-cpp-3.19.1.zip),解压并用cmake编译(如果用make直接编译会找不到libprotoc.so。Error while loading shared libraries: libprotoc.so.xx: cannot open shared object file: No):
unzip protobuf-cpp-3.19.1.zip
cd protobuf-3.19.1/cmake
mkdir build && cd build && cmake .. && cd ..
make
sudo make install
如果你想使用最新版,安装教程可以参考C++ Installation官网
我们使用了官方用例进行构建:Protocol Buffer Basics: C++
首先创建文件addressbook.proto:
syntax = "proto2"; package tutorial; message Person { optional string name = 1; optional int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { optional string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; }
创建CMakeLists.txt:
# Minimum CMake required cmake_minimum_required(VERSION 2.8) # Project project(Person) # Find required protobuf package find_package(Protobuf REQUIRED) if (PROTOBUF_FOUND) message(STATUS "protobuf library found") else () message(FATAL_ERROR "protobuf library is needed but cant be found") endif () include_directories(${PROTOBUF_INCLUDE_DIRS}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS addressbook.proto) message(${PROTO_SRCS} ${PROTO_HDRS}) add_executable(Person Person.cpp ${PROTO_SRCS} ${PROTO_HDRS}) target_link_libraries(Person ${PROTOBUF_LIBRARIES})
创建Person.cpp:
#include <iostream> #include <fstream> #include <string> #include "addressbook.pb.h" using namespace std; // This function fills in a Person message based on user input. void PromptForAddress(tutorial::Person *person) { cout << "Enter person ID number: "; int id; cin >> id; person->set_id(id); cin.ignore(256, '\n'); cout << "Enter name: "; getline(cin, *person->mutable_name()); cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty()) { person->set_email(email); } while (true) { cout << "Enter a phone number (or leave blank to finish): "; string number; getline(cin, number); if (number.empty()) { break; } tutorial::Person::PhoneNumber *phone_number = person->add_phones(); phone_number->set_number(number); cout << "Is this a mobile, home, or work phone? "; string type; getline(cin, type); if (type == "mobile") { phone_number->set_type(tutorial::Person::MOBILE); } else if (type == "home") { phone_number->set_type(tutorial::Person::HOME); } else if (type == "work") { phone_number->set_type(tutorial::Person::WORK); } else { cout << "Unknown phone type. Using default." << endl; } } } // Main function: Reads the entire address book from a file, // adds one person based on user input, then writes it back out to the same // file. int main(int argc, char *argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!input) { cout << argv[1] << ": File not found. Creating a new file." << endl; } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } // Add an address. PromptForAddress(address_book.add_people()); { // Write the new address book back to disk. fstream output(argv[1], ios::out | ios::trunc | ios::binary); if (!address_book.SerializeToOstream(&output)) { cerr << "Failed to write address book." << endl; return -1; } } // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }
在当前目录打开终端并输入:
cmake ./ && make
./Person people.data
这时我们会看到:
于是你输入的数据就会保存在people.data里面
之后我们修改Person.cpp为:
#include <iostream> #include <fstream> #include <string> #include "addressbook.pb.h" using namespace std; // Iterates though all people in the AddressBook and prints info about them. void ListPeople(const tutorial::AddressBook &address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person &person = address_book.people(i); cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.has_email()) { cout << " E-mail address: " << person.email() << endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber &phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: cout << " Mobile phone #: "; break; case tutorial::Person::HOME: cout << " Home phone #: "; break; case tutorial::Person::WORK: cout << " Work phone #: "; break; } cout << phone_number.number() << endl; } } } // Main function: Reads the entire address book from a file and prints all // the information inside. int main(int argc, char *argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } ListPeople(address_book); // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }
在当前目录打开终端并输入:
cmake ./ && make
./Person people.data
这时我们会看到:
我们从官网下载最新的Download Protocol Buffers(官方用例)作为例子如下(参考CMake官网Documentation » cmake-modules(7) » FindProtobuf):
首先创建addressbook.proto:
// See README.txt for information and build instructions. // // Note: START and END tags are used in comments to define sections used in // tutorials. They are not part of the syntax for Protocol Buffers. // // To get an in-depth walkthrough of this file and the related examples, see: // https://developers.google.com/protocol-buffers/docs/tutorials // [START declaration] syntax = "proto3"; package tutorial; import "google/protobuf/timestamp.proto"; // [END declaration] // [START java_declaration] option java_multiple_files = true; option java_package = "com.example.tutorial.protos"; option java_outer_classname = "AddressBookProtos"; // [END java_declaration] // [START csharp_declaration] option csharp_namespace = "Google.Protobuf.Examples.AddressBook"; // [END csharp_declaration] // [START go_declaration] option go_package = "../tutorial"; // [END go_declaration] // [START messages] message Person { string name = 1; int32 id = 2; // Unique ID number for this person. string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { string number = 1; PhoneType type = 2; } repeated PhoneNumber phones = 4; google.protobuf.Timestamp last_updated = 5; } // Our address book file is just one of these. message AddressBook { repeated Person people = 1; } // [END messages]
CMakeLists.txt:
# Minimum CMake required cmake_minimum_required(VERSION 3.8) # Project project(protobuf-examples) # Find required protobuf package find_package(Protobuf REQUIRED) if (PROTOBUF_FOUND) message(STATUS "protobuf library found") else () message(FATAL_ERROR "protobuf library is needed but cant be found") endif () set(CMAKE_INCLUDE_CURRENT_DIR TRUE) # http://www.cmake.org/Wiki/CMake_FAQ#How_can_I_build_my_MSVC_application_with_a_static_runtime.3F if (MSVC AND protobuf_MSVC_STATIC_RUNTIME) foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if (${flag_var} MATCHES "/MD") string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") endif (${flag_var} MATCHES "/MD") endforeach () endif () foreach (example add_person list_people) set(${example}_SRCS ${example}.cc) set(${example}_PROTOS addressbook.proto) #Code Generation if (protobuf_MODULE_COMPATIBLE) #Legacy Support protobuf_generate_cpp(${example}_PROTO_SRCS ${example}_PROTO_HDRS ${${example}_PROTOS}) list(APPEND ${example}_SRCS ${${example}_PROTO_SRCS} ${${example}_PROTO_HDRS}) endif () #Executable setup set(executable_name ${example}_cpp) add_executable(${executable_name} ${${example}_SRCS} ${${example}_PROTOS}) if (protobuf_MODULE_COMPATIBLE) #Legacy mode target_include_directories(${executable_name} PUBLIC ${PROTOBUF_INCLUDE_DIRS}) target_link_libraries(${executable_name} ${PROTOBUF_LIBRARIES}) else () target_link_libraries(${executable_name} protobuf::libprotobuf) protobuf_generate(TARGET ${executable_name}) endif () endforeach ()
add_person.cc
// See README.txt for information and build instructions. #include <ctime> #include <fstream> #include <google/protobuf/util/time_util.h> #include <iostream> #include <string> #include "addressbook.pb.h" using namespace std; using google::protobuf::util::TimeUtil; // This function fills in a Person message based on user input. void PromptForAddress(tutorial::Person *person) { cout << "Enter person ID number: "; int id; cin >> id; person->set_id(id); cin.ignore(256, '\n'); cout << "Enter name: "; getline(cin, *person->mutable_name()); cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty()) { person->set_email(email); } while (true) { cout << "Enter a phone number (or leave blank to finish): "; string number; getline(cin, number); if (number.empty()) { break; } tutorial::Person::PhoneNumber *phone_number = person->add_phones(); phone_number->set_number(number); cout << "Is this a mobile, home, or work phone? "; string type; getline(cin, type); if (type == "mobile") { phone_number->set_type(tutorial::Person::MOBILE); } else if (type == "home") { phone_number->set_type(tutorial::Person::HOME); } else if (type == "work") { phone_number->set_type(tutorial::Person::WORK); } else { cout << "Unknown phone type. Using default." << endl; } } *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL)); } // Main function: Reads the entire address book from a file, // adds one person based on user input, then writes it back out to the same // file. int main(int argc, char *argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!input) { cout << argv[1] << ": File not found. Creating a new file." << endl; } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } // Add an address. PromptForAddress(address_book.add_people()); { // Write the new address book back to disk. fstream output(argv[1], ios::out | ios::trunc | ios::binary); if (!address_book.SerializeToOstream(&output)) { cerr << "Failed to write address book." << endl; return -1; } } // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }
list_people.cc
// See README.txt for information and build instructions. #include <fstream> #include <google/protobuf/util/time_util.h> #include <iostream> #include <string> #include "addressbook.pb.h" using namespace std; using google::protobuf::util::TimeUtil; // Iterates though all people in the AddressBook and prints info about them. void ListPeople(const tutorial::AddressBook &address_book) { for (int i = 0; i < address_book.people_size(); i++) { const tutorial::Person &person = address_book.people(i); cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.email() != "") { cout << " E-mail address: " << person.email() << endl; } for (int j = 0; j < person.phones_size(); j++) { const tutorial::Person::PhoneNumber &phone_number = person.phones(j); switch (phone_number.type()) { case tutorial::Person::MOBILE: cout << " Mobile phone #: "; break; case tutorial::Person::HOME: cout << " Home phone #: "; break; case tutorial::Person::WORK: cout << " Work phone #: "; break; default: cout << " Unknown phone #: "; break; } cout << phone_number.number() << endl; } if (person.has_last_updated()) { cout << " Updated: " << TimeUtil::ToString(person.last_updated()) << endl; } } } // Main function: Reads the entire address book from a file and prints all // the information inside. int main(int argc, char *argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } ListPeople(address_book); // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0; }
在当前目录打开终端并输入:
cmake ./ && make
./add_person_cpp people.data
这时我们会看到:
之后我们输入:
./list_people_cpp people.data
这时我们会看到:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。