C++使用ProtoBuff(VS2017 + ProtoBuff3.13 + X64)

下载ProtoBuff

  1. 从github下载:

https://github.com/protocolbuffers/protobuf

说明:
直接clone下来的代码,没有子模块(引用的其他第三方模块的代码),比如third_party/googletest;

  1. 建议直接下载release最新版:
    https://github.com/protocolbuffers/protobuf/releases

编译ProtoBuff

  1. 解压protobuf-3.13.0后,命令行进入protobuf-3.13.0目录
    cd D:\work\program\open_source\protobuf-all-3.13.0\protobuf-3.13.0
  2. 新建一个编译输出路径
    mkdir build_1 && cd build_1
  3. 执行cmake, 生成VS2017工程文件;
    "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" ../cmake -G "Visual Studio 15 2017 Win64"

说明:
-G "Visual Studio 15 2017 Win64" 表示生成VS2017 X64工程;
../cmake 表示CMakeLists.txt文件的路径

  1. 生成include文件
    extract_includes.bat

  2. 打开build_1/protobuf.sln,进行编译

这样,就得到了我们需要的头文件protoc.exelibprotobufd.lib(PS:libprotobuf只提供了静态库),在如下两个目录:
protobuf-3.13.0/build_1/Debug
protobuf-3.13.0/build_1/include

注意:
Protobuf的所有工程默认运行库是MT/MTd,建议都改成MD/MDd;
如果不修改,那么你的工程也必须设置成MT/MTd才能编译通过,这样如果在使用其他动态库时,很容易导致一些堆错误,因为动态库相对应用有独立heap;


image.png

使用ProtoBuff

  1. 先把生成的Debug和include拷贝到工程目录


    image.png

PS:D:\work\program\Serialization\Serialization是我的测试工程目录*

  1. 添加一个测试proto文件
    Serialization\protobuff_files\AddressBook.proto
syntax = "proto3";

package tutorial;

message Person {
  string name = 1;
  int32 id = 2;
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}
  1. 编译proto文件
    进入测试工程目录
    cd D:\work\program\Serialization\Serialization
    使用编译生成的protoc.exe编译proto文件
    protobuf-3.13.0\x64\Debug\protoc.exe -I=Serialization\protobuff_files --cpp_out=Serialization\protobuff_files AddressBook.proto

说明:
protoc编译.proto文件命令格式:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR xxx1.proto xxx2.proto
$SRC_DIR:包含相关的所有.proto文件,一般为工程目录;
$DST_DIR:生成的源文件的目录,可以与$SRC_DIR相同;
xxx1.proto:proto文件在$SRC_DIR中的相对路径,也可以是绝对路径;

编译proto文件后,会生成对应的.pb.cc和.pb.h文件:

image.png

  1. 应用工程设置
    PS:老手请跳过此步;
  • 包含include目录:$(ProjectDir)..\protobuf-3.13.0\x64\include;


    image.png
  • 添加库目录:$(ProjectDir)..\protobuf-3.13.0\x64\Debug;


    image.png
  • 添加附加依赖项:libprotobufd.lib;


    image.png
  • 添加编译proto生成的AddressBook.pb.cc和AddressBook.pb.h到工程:


    image.png
  1. 使用ProtoBuff示例
    代码可以直接拷贝运行
/************************************************************************
* 测试ProtoBuff
* 
* 
* 从didi_AddressBook.txt中读取通讯录,然后添加一条记录,最后再写入文件;
* 如果didi_AddressBook.txt不存在,第一次添加记录后,会创建文件didi_AddressBook.txt
* 
************************************************************************/


#include 
#include 
#include 
#include "protobuff_files/AddressBook.pb.h"
using namespace std;

// 打印AddressBook
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;
        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;
        }
    }
}

// 通讯录增加一个人
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;
        }
    }
}

// 从didi_AddressBook.txt中读取通讯录,然后添加一条记录,最后再写入文件;
// 如果didi_AddressBook.txt不存在,第一次添加记录后,会创建文件didi_AddressBook.txt
int main(int argc1, char* argv1[]) {
    // 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;

    char file_name[] = "didi_AddressBook.txt";

    tutorial::AddressBook address_book;

    {
        // Read the existing address book.
        fstream input(file_name, ios::in | ios::binary);
        if (!input) {
            cout << file_name << ": File not found.  Creating a new file." << endl;
        }
        else if (!address_book.ParseFromIstream(&input)) {
            cerr << "Failed to parse address book." << endl;
            return -1;
        }
    }

    //打印address_book
    {
        int people_size = address_book.people_size();
        cout << "print address_book by ListPeople(): " << people_size << endl;
        ListPeople(address_book);

        //也可以使用基类Message中提供的方法:
        string debug_string = address_book.DebugString();
        cout << "print address_book by PrintDebugString(): " << endl;
        address_book.PrintDebugString();

        address_book.Clear();
        cout << "after Clear, print address_book by PrintDebugString(): " << endl;
        address_book.PrintDebugString();
        cout << endl;
    }

    // Add an address.
    cout << "begin add a address:" << endl;
    PromptForAddress(address_book.add_people());

    {
        // Write the new address book back to disk.
        fstream output(file_name, 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;
}

可以看到ProtoBuff序列化后的内容如下:

image.png

你可能感兴趣的:(C++使用ProtoBuff(VS2017 + ProtoBuff3.13 + X64))