Windows Protobuf C++ 示例

1. Protobuf Installation

看到CMake越来越流行,我还真是有点沾沾自喜。谁让我那么早就看上它了。现在越来越多的开源库在支持CMake,Protobuf也是其中一员。使用CMake,可以非常轻松地将Protobuf构建起来。具体的构建方式如下:

  • 下载Protobuf: 使用git clone将Protobuf下载到自建的某个目录中。
F:\OpenSource\protobuf>git clone https://github.com/google/protobuf.git .
  • CMAKE: 这个是重点。如果还不太熟悉的话,可以查看我之前翻译的CMake的教程。我使用的编译器是VS2015 x64。
    《Windows Protobuf C++ 示例》
    其中,
    • protobuf_BUILD_SHARED_LIBS决定了最终构建为静态库还是动态库,
    • protobuf_MSVC_STATIC_RUNTIME决定了使用静态的MSVC运行时库还是使用动态的MSVC运行时库。我暂时使用动态的MSVC运行时库。

然后点击Configure以及Generate。此时,在F:\OpenSource\protobuf\VC14中就生成了protobuf.sln。打开它。

  • 编译: 运行ALL_BUILD,经过了不算长的编译之后,输出面板显示好消息,全部成功。

《Windows Protobuf C++ 示例》 生成ALL_BUILD
《Windows Protobuf C++ 示例》 生成成功

  • 安装:最后是安装环节,把零散的东西放到一起是安装环节的最重要的意义。同样成功。
    《Windows Protobuf C++ 示例》 生成INSTALL
    《Windows Protobuf C++ 示例》 安装目录

2. Building examples

接着,来把例子试一试吧~进入install目录下的examples文件夹。我们看到,有.cc, .go, .py, .java四种后缀。对应着C++, GO, Python, Java四种语言。我们仅来尝试C++的版本。看到文件夹中有CMakeLists.txt。因此,仍然使用CMake。

《Windows Protobuf C++ 示例》 例子文件夹
《Windows Protobuf C++ 示例》 CMake(1)

此时会报错,因为找不到protobuf_DIR。手动选择即可。

《Windows Protobuf C++ 示例》 CMake(2)

再按
Configure,
Generate即可。

《Windows Protobuf C++ 示例》 CMake(3)

打开build\protobuf-examples.sln。生成ALL_BUILD。全部成功。

此时,即可调试例子了。先看add_person_cpp

《Windows Protobuf C++ 示例》 add_person_cpp属性页

在属性的命令参数中添加addressbook。如此,会将结果输出到addressbook中。运行add_person_cpp。

《Windows Protobuf C++ 示例》 运行add_person_cpp(1)
《Windows Protobuf C++ 示例》 运行add_person_cpp(2)

同样的,在list_people_cpp的属性页中增加命令参数addressbook,来读取addressbook的参数。运行list_people_cpp。

《Windows Protobuf C++ 示例》 list_people_cpp属性页
《Windows Protobuf C++ 示例》 list_people_cpp运行结果

本着DRY(Don’t Repeat yourself)原则,就不进行代码的解读了,若需要对代码详情进一步了解的,请转向官方网站文档

3. Prototxt introduction

想接触ProtoBuf完全是为了Caffe,谁让Caffe用了这玩意儿呢。但Caffe还用到了.prototxt格式来存储信息,而上文中却还尚未提及。因此,有必要继续尝试。在网上翻查了一些资料后,我写下了如下的例子来把整个文章的内容串起来。

#include <string>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include "addressbook.pb.h"
#include <fstream>
#include <iostream>
#include <io.h>
#include <windows.h>
 
using namespace std;
 
#ifdef _MSC_VER
#define open _open
#define close _close
#endif
 
namespace tutorial{
    using google::protobuf::io::FileInputStream;
    using google::protobuf::io::FileOutputStream;
    using google::protobuf::io::ZeroCopyInputStream;
    using google::protobuf::io::CodedInputStream;
    using google::protobuf::io::ZeroCopyOutputStream;
    using google::protobuf::io::CodedOutputStream;
    using google::protobuf::Message;
 
    bool ReadProtoFromTextFile(const char* filename, Message* proto){
        int fd = open(filename, O_RDONLY);
        if (fd == -1)
            cerr << "File not found: " << filename;
        FileInputStream* input = new FileInputStream(fd);
        bool success = google::protobuf::TextFormat::Parse(input, proto);
        delete input;
        close(fd);
        return success;
    }
 
    void WriteProtoToTextFile(const Message& proto, const char* filename){
        int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        FileOutputStream* output = new FileOutputStream(fd);
        google::protobuf::TextFormat::Print(proto, output);
        delete output;
        close(fd);
    }
 
    // Iterates though all people in the AddressBook and prints info about them.
    void ListPeople(const 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 Person::PhoneNumber& phone_number = person.phones(j);
 
                switch (phone_number.type()) {
                case Person::MOBILE:
                    cout << "  Mobile phone #: ";
                    break;
                case Person::HOME:
                    cout << "  Home phone #: ";
                    break;
                case Person::WORK:
                    cout << "  Work phone #: ";
                    break;
                }
                cout << phone_number.number() << endl;
            }
        }
    }
 
    // This function fills in a Person message based on user input.
    void PromptForAddress(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;
            }
 
            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(Person::MOBILE);
            }
            else if (type == "home") {
                phone_number->set_type(Person::HOME);
            }
            else if (type == "work") {
                phone_number->set_type(Person::WORK);
            }
            else {
                cout << "Unknown phone type.  Using default." << endl;
            }
        }
    }
}
 
int main(int argc, char* argv[])
{
    GOOGLE_PROTOBUF_VERIFY_VERSION;
 
    string ans;
 
    if (argc != 2) {
        cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
        return -1;
    }
    tutorial::AddressBook address_book;
    tutorial::ReadProtoFromTextFile(argv[1], &address_book);
 
    tutorial::ListPeople(address_book);
 
    cout << "Want to add new person?" << endl;
    cin >> ans;
 
    tutorial::Person person;
    if (ans == "yes" || ans == "y")
    {
        tutorial::PromptForAddress(address_book.add_people());
        tutorial::WriteProtoToTextFile(address_book, argv[1]);
    }
    else if (ans == "no" || ans == "n")
    {
        return 0;
    }
    else
    {
        cout << "Please input yes or no!" << endl;
        return 0;
    }
    return 0;
}

这个程序首先从.prototxt文件中读取数据,然后列出读取到的内容,询问是否增加人员,最后将结果输出回.prototxt的文件中。.prototxt的样子是这样的:

people {
  name: "xingzhi"
  id: 1
  email: "xingzhi@xxx.com"
  phones {
    number: 1231234123
    type: HOME
  }
  phones {
    number: 4564567456
    type: WORK
  }
}
 
people {
  name: "yi-an"
  id: 2
  email: "yi-an@xxx.com"
  phones {
    number:7897890789
    type:MOBILE
  }
}

后来我增加了一个xyz的联系人,输出之后的结果为:

people {
  name: "xingzhi"
  id: 1
  email: "xingzhi@xxx.com"
  phones {
    number: "1231234123"
    type: HOME
  }
  phones {
    number: "4564567456"
    type: WORK
  }
}
people {
  name: "yi-an"
  id: 2
  email: "yi-an@xxx.com"
  phones {
    number: "7897890789"
  }
}
people {
  name: "xyz"
  id: 3
  email: "xyz@xxx.com"
  phones {
    number: "12345678901"
    type: HOME
  }
}

完美!利用这样的prototxt,非常方便人工修改。

    原文作者:行之与亦安
    原文地址: https://www.jianshu.com/p/26b134ee78e4
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞