在Ubuntu上使用protobuf(C++)

一、protobuf的下载和解压

protobuf提供了一些发布的版本,可以从里面下载指定语言的压缩包。

例如:

wget https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-cpp-3.21.7.zip
unzip protobuf-cpp-3.21.7.zip
二、protobuf的安装

在上面解压的文件夹下,是有一个README.md文件的,里面介绍了安装的方式,主要是:

To build protobuf from source, the following tools are needed:

  • autoconf
  • automake
  • libtool
  • make
  • g++
  • unzip

On Ubuntu/Debian, you can install them with:

sudo apt-get install autoconf automake libtool curl make g++ unzip

To build and install the C++ Protocol Buffer runtime and the Protocol

Buffer compiler (protoc) execute the following:

./configure

make -j$(nproc) # $(nproc) ensures it uses all cores for compilation

make check

sudo make install

sudo ldconfig # refresh shared library cache.

By default, the package will be installed to /usr/local.

可以在终端上输入protoc --version查看安装成功与否。

三、使用示例

示例主要来自文件夹examples下的addressbook.proto

  • 定义protobuf源文件,addressbook.proto
// [START declaration]
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";
// [END 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]

这个文件主要的作用是定义了protobuf结构。

可以看到最后面,电话本(AddressBook)里面定义了Person结构,其repeated代表了电话本可以包含多个Person

  • 编译proto源文件

在源文件目录下执行以下编译命令:

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

执行完后,会生成一个.cc和一个.h文件

在这里插入图片描述

生成的文件主要包含了结构体成员设置和格式转换的接口,下面展示一下如何使用。

  • 接口使用示例
  1. 测试写入文件testwrite.cc
#include 
#include 
#include 
#include 
#include 

#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;
}

通过以下命令编译,testread同理

g++ testwrite.cc addressbook.pb.cc -o testwrite -lprotobuf

运行可执行文件:

./testwrite addressbook.data

输入信息即可,查看addressbook.data,可以看到打包的数据。

在Ubuntu上使用protobuf(C++)_第1张图片

  1. 测试读文件testread.cc:
#include 
#include 
#include 
#include 

#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;
}

运行可执行文件testread,读出addressbook.data中的信息,也就是反序列化。

./testread addressbook.data

output:

Person ID: 1
  Name: wzm
  E-mail address: 12345
  Mobile phone #: 11111
  Mobile phone #: sfafsa
  Mobile phone #: qqwq
  Mobile phone #: saf
  Updated: 2022-09-30T08:37:46Z
四、参考资料

关于proto源文件的写法及更多介绍,可以参考官方源码或官方教程

你可能感兴趣的:(C++项目,ubuntu,c++,linux)