woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

在C++中使用Google的“Protocol Buffers”

如果您已经初步了解了Protocol Buffers并打算试着使用它,本文符合您的胃口。如果您刚听说Protocol Buffers,请先到本文末尾的附录区看一看。

1.下载并安装Protocol Buffers

可以从官方下载源码包,linux下和Solaris下的安装直接见源码包中的“README.txt”。这里详细说下Windows下的安装,源码包里有一个“vsprojects”目录,其中就是vs的工程文件和解决方案。用vs(版本得高点)打开“protobuf.sln”解决方案,编译。其中包括四个工程 libprotobuf(接口dll库)、libprotoc(转换器的实现库)、protocwindows下转换器的实现)、tests(使用gTest库进行的测试)。编译好之后在Debug目录下可以找到“libprotobuf.dlllibprotobuf.lib”,这个是我们的程序要使用的动态链接库和导入库。“libprotoc.dlllibprotoc.lib”,这个是完成.proto文件到cppjavapython格式数据转换的库。“protoc.exe”,这个是windows下转换程序(它使用了刚才的libprotoc),这个程序的静态链接版本也在此项目老家提供下载。

2.设置编译环境

    linux下,只要将Protocol Buffers源码包安装到系统即可开始使用。而windows下需要设置一下编译环境,将“src”目录加入到编译器的头文件搜索路径,将“vsprojects\Debug”目录加入到编译器的lib搜索路径中。为了更方便的在windows命令行下使用protoc.exe转换程序,可以将“vsprojects\Debug”目录添加到系统PATH变量中。

3.编写.proto数据描述文件

    这里仿照源码中例子,写出“addressbook.proto”文件。内容如下:

--code begin--

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;

}

--code end--

4.使用protoc(windows下是protoc.exe)生成c++头文件及类文件。

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

如果没有错误,程序将没有任何输出。并且当前目录下多出两个文件“addressbook.pb.h”“addressbook.pb.cc”

5.编写C++程序使用它们

    新建vs工程,除了设置以上的头文件搜索路径和库文件搜索路径外,还要链接到库“libprotobuf.lib”。将4步生成的一个.h文件和一个.cpp文件添加并拷贝到工程里,由于vs的特性(需要预编译头),所以在addressbook.pb.cc开头添加“#include "stdafx.h"”,主代码如下,然后编译。这个演示程序需要一个参数用于指定数据文件文件名,第一次运行,会生成这个数据文件。它会先让用户输入一条通讯录信息并添加进数据文件,然后再显示出指定的数据文件中所有的数据。注意,为了使DEMO程序可以运行,别忘了拷贝“vsprojects\Debug”目录下的动态链接库“libprotobuf.dll”到当前目录。

--code begin--

// testprotocolbuffer.cpp : 定义控制台应用程序的入口点。

//

 

#include "stdafx.h"

 

// See README.txt for information and build instructions.

 

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

    }

  }

}

 

// 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,

//   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 << "使用方法:  " << argv[0] << " 想要生成的存储数据的文件" << 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] << ": 指定的文件没找到,创建一个新文件." << endl;

    } else if (!address_book.ParseFromIstream(&input)) {

      cerr << "解析addressbook数据文件失败。" << 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 << "写入文件失败。" << endl;

      return -1;

    }

  }

 

  //再从文件中读取刚才那个数据

  tutorial::AddressBook address_book2;

 

  {

    // Read the existing address book.

    fstream input(argv[1], ios::in | ios::binary);

    if (!address_book2.ParseFromIstream(&input)) {

      cerr << "解析文件失败。" << endl;

      return -1;

    }

  }

 

  ListPeople(address_book2);

 

  return 0;

}

--code end--

运行方式和结果如下图:

clip_image001

备注:写这东西好累啊。。。

=====================附录====================

1.Protocol BuffersGoogle自己的一种数据交换格式。其简介可以参考文章谷歌发布内部数据语言 比XML快近100

2.如果想要了解Protocol Buffers相关的详细信息,请访问它的老家Protocol Buffers

 

posted on 2009-08-20 23:58 肥仔 阅读(3310) 评论(0)  编辑 收藏 引用 所属分类: 网络编程


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理