1. 程式人生 > >google protocol學習總結

google protocol學習總結

安裝protocol 

sudo apt-get install libprotobuf-dev protobuf-compiler 

ubuntu16.04 因為之前安裝過ros 所以系統中有預設的 protobuf ,至於使用哪個版本的protocol,可以自己設定,參考

Ubuntu解除安裝並重新安裝protocol

安裝完成 protoc –version 

libprotoc 2.6.1

which protoc 可以檢視 protoc的安裝路徑

protocol是一個完全抽象的資料儲存和讀取的包,獨立於作業系統,獨立於語言。所以不論是linux還是win,不論是c++ python c# java R GO 都可以使用。

其儲存形式是二進位制檔案,所以相比於xml,對於相同的資料,能節約3-10倍空間,儲存和讀取效率高20-100倍。

舉個例子:

資料來源

xml

  <person>
    <name>John Doe</name>
    <email>[email protected]</email>
  </person>

protocol

# Textual representation of a protocol buffer.
# This is *not* the binary format used on the wire.
person {
  name: "John Doe"
  email: "
[email protected]
" }

輸出

xml

  cout << "Name: "
       << person.getElementsByTagName("name")->item(0)->innerText()
       << endl;
  cout << "E-mail: "
       << person.getElementsByTagName("email")->item(0)->innerText()
       << endl;

protocol

  cout << "Name: " << person.name() << endl;
  cout << "E-mail: " << person.email() << endl;

下面是對tutorial的一些搬運:

最重要的三點:

  • Define message formats in a .proto file.
  • Use the protocol buffer compiler.
  • Use the C++ protocol buffer API to write and read messages. 

檔案是.proto形式,就像上面看到的那樣

.proto形式的檔案還不能直接使用,因為這個是抽象的,獨立於平臺和語言,所以有一個編譯器,自動把.proto檔案翻譯成平臺下你要的語言,我這裡是cpp。

直接呼叫編譯器生成的.cc和.h檔案,壓根不用關心內怎麼實現的,反正編譯器幫你做好了,你要做的就是呼叫API。

首先在空資料夾中新建一個addressbook.proto

內容如下
 

package tutorial;
 
message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
 
  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }
 
  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }
 
  repeated PhoneNumber phone = 4;
}
 
message AddressBook {
  repeated Person person = 1;
}

原始資料型別可以是boolint32floatdouble, andstring

其他資料型別也可以一級一級包含,在程式碼中已經很明確了。

package tutorial;

意思是名稱空間namespace
required宣告的變數是必須被初始化的,如果沒有初始化,在debug模式下會報錯。

optional宣告的變數是可以選擇性初始化。

repeated宣告的變數是可以重複新增的。

注意一些=1 =2 =3,是一種定址機制,1-15在生成的bin中,可以快速的被讀取和寫入,所以重複使用的資料儘量放在1-15號。

下面就是編譯了,注意這兒的編譯只是將.proto檔案翻譯成我們要的檔案,並不是生成什麼可執行程式。
 

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

我的是

protoc -I=./ --cpp_out=./ ./addressbook.proto

之後會生成兩個檔案分別是addressbook.pb.h addressbook.pb.cc

這裡不在貼出具體生成程式碼.

之後就是呼叫API了

Standard Message Methods
Each message class also contains a number of other methods that let you check or manipulate the entire message, including:

  • bool IsInitialized() const;: checks if all the required fields have been set.
  • string DebugString() const;: returns a human-readable representation of the message, particularly useful for debugging.
  • void CopyFrom(const Person& from);: overwrites the message with the given message's values.
  • void Clear();: clears all the elements back to the empty state.

These and the I/O methods described in the following section implement the Message interface shared by all C++ protocol buffer classes. For more info, see thecomplete API documentation for Message.        


Parsing and Serialization
Finally, each protocol buffer class has methods for writing and reading messages of your chosen type using the protocol bufferbinary format. These include:

  • bool SerializeToString(string* output) const;: serializes the message and stores the bytes in the given string. Note that the bytes are binary, not text; we only use thestring class as a convenient container.
  • bool ParseFromString(const string& data);: parses a message from the given string.
  • bool SerializeToOstream(ostream* output) const;: writes the message to the given C++ostream.
  • bool ParseFromIstream(istream* input);: parses a message from the given C++istream.

These are just a couple of the options provided for parsing and serialization. Again, see theMessage API reference for a complete list.       


最後就是寫一個測試程式碼了。

新建一個test1.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_phone();
    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_person());
 
  {
    // 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;
}


程式碼其實就是新建了一個聯絡人,裡面可以放許多聯絡人,電話,email。

然後這樣子編譯。好像使用aptget install並不能讓g++自動找到.so檔案。所以手動設定路徑。

g++ test1.cpp addressbook.pb.cc -L /usr/lib/x86_64-linux-gnu -l protobuf -o test1

執行以後會生成一個二進位制檔案。這個檔案也是protocol的最終產物了。一個寫入和載入速度最快,體積最小的東西。

下面一段程式是讀取這個檔案的內容。

#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.person_size(); i++) {
    const tutorial::Person& person = address_book.person(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.phone_size(); j++) {
      const tutorial::Person::PhoneNumber& phone_number = person.phone(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;
}

 

參考連結:

https://blog.csdn.net/u010566411/article/details/52841460