1.下載安裝: html
google protocol buffer 的官網地址是:http://code.google.com/p/protobuf/ java
建議下載穩定版本:protobuf-2.4.1 linux下載protobuf-2.4.1.tar.bz2 windows下載protobuf-2.4.1.zip python
這裏以linux下安裝爲實例: mysql
tar -xvf protobuf-2.4.1.tar.bz2 linux
cd protobuf-2.4.1 ios
./configure --prefix=/usr/local/protobuf-2.4.1 c++
make redis
make install 算法
2.使用protobuf sql
查看編譯生成的目錄
cd /usr/local/protobuf-2.4.1
ls
bin include lib
其中,bin中的protoc是.proto文件的處理器,可用這個工具生成cpp,java,python文件.
因爲系統經常使用這個工具,能夠將其ln或者直接拷貝到系統環境bin下
ln -s /usr/local/protobuf-2.4.1/bin/protoc /usr/bin/protoc
一樣,能夠將頭文件ln或者直接拷貝到系統環境
ln -s /usr/local/protobuf-2.4.1/include/google /usr/include/google
將lib文件ln或者直接拷貝到系統環境
略,方法同上.
這個時候,protobuf的開發環境已經搭建了.
3.如何使用protobuf
- 數據結構體:
- message message_name{message_body;}
- message_body格式:
- 例如required int32 query = 1[defaut=10];
- 形式爲:rule type name = value[other_rule];
- 規則:
- required表示必須具備該值域;
- optional表示可選的值域;
- repeated表示可重複的值域(即>=0);
- 其中requered/optional是經常使用rule,而repeated則不經常使用同時由於是歷史遺留現使用repeated int32 samples=4[packed=true];形式;
-
- value值:
- value值最小爲1,是底層編碼時使用其中1-15佔一位,>15則會佔多位;
- 不一樣的message中的value值互不干擾,常以1開始計數。
-
- 數據類型之基本類型:
- .proto Type C++ Type Java Type
- double double double
- float float float
- int32 int32 int
- int64 int64 long
- uint32 uint32 int
- uint64 uint64 long
- sint32 int32 int
- sint64 int64 long
- fixed32 uint32 int
- fixed64 uint64 long
- sfixed32 int32 int
- sfixed64 int64 long
- bool bool boolean
- string string String
- bytes string ByteString
-
- 數據類型之複雜類型:
- 複雜類型主要包括:枚舉,其餘message,groups等。
- 枚舉定義例如:enum Corpus{WEB=0;LOCAL=1}
- 枚舉定義在message中。
- 能夠使用其餘message做爲類型來定義成員。
- groups個人理解有些像C++中的union結構。
-
- 嵌套定義:
- 能夠嵌套定義message結構,而嵌套定義的message被其餘message做爲成員類型時須要形式爲outmessage.inmessage形式。
-
- 包結構:
- 定義形式:package foo.bar;
- 對應C++中則生成兩個命名空間foo和bar,且bar定義在foo中;
- 能夠經過import "myproject/other_protos.proto";來引入.proto文件;
- 引用其餘package中message時須要完整的package路徑;
-
- Services:
- 主要用於RPC系統中,在.proto中定義接口;
- 定義形式如例子:
- service SearchService {
- rpc Search(SearchRequest) return (SearchResponse);
- }
-
- .proto文件編譯:
- 格式:
- protoc -–proto_path=(.proto文件路徑) -–cpp_out=(.cc .java生成文件路徑) (.proto文件路徑)/?.proto
- -–proto_path 簡化爲: --I
- 其中可根據須要更改:cpp_out選項爲java_out/python_out。
- 例子:
- protoc -I=./ --cpp_out=./ model.proto
咱們拿個例子:
創建model.proto
- package cn.vicky.model.seri;
-
- message User {
- required int32 id = 1; // 主鍵,惟一
- required string username = 2; // 賬號
- required string password = 3; // 密碼
- optional string email = 4; // 郵箱(可選)
- repeated Person person = 5; // 帳戶擁有的角色(能夠重複)
- }
-
- message Person {
- required int32 id = 1; // 主鍵,惟一
- required string name = 2; // 角色名字
-
- repeated PhoneNumber phone = 3; // 電話號碼(能夠重複)
- }
-
- // 枚舉類型
- enum PhoneType {
- MOBILE = 0;
- HOME = 1;
- WORK = 2;
- }
-
- message PhoneNumber {
- required string number = 1;
- optional PhoneType type = 2 [default = HOME];
- }
protoc -I=./ --cpp_out=./ model.proto
將生成對應的model.pb.h model.pb.cc
使用:
編寫main.cpp
- /*
- * File: main.cpp
- * Author: Vicky.H
- * Email: eclipser@163.com
- */
- #include <iostream>
- #include <fstream>
- #include "model.pb.h"
-
- /*
- *
- */
- int main(void) {
-
- // 建立User對象
- cn::vicky::model::seri::User u;
- u.set_id(1);
- u.set_username("Jack");
- u.set_password("123456");
- u.set_email("289997171@qq.com");
-
- // 建立User中的一個角色
- cn::vicky::model::seri::Person* _person1 = u.add_person();
- _person1->set_id(1);
- _person1->set_name("P1");
-
- // 建立角色中的一個電話號碼:1
- cn::vicky::model::seri::PhoneNumber* _phone1 = _person1->add_phone();
- _phone1->set_number("+8613618074943");
- _phone1->set_type(cn::vicky::model::seri::MOBILE);
-
- // 建立角色中的一個電話號碼:2
- cn::vicky::model::seri::PhoneNumber* _phone2 = _person1->add_phone();
- _phone2->set_number("02882334717");
- _phone2->set_type(cn::vicky::model::seri::WORK);
-
-
- // 建立User中的一個角色
- cn::vicky::model::seri::Person* _person2 = u.add_person();
- _person2->set_id(2);
- _person2->set_name("P2");
-
- // 建立角色中的一個電話號碼:1
- cn::vicky::model::seri::PhoneNumber* _phone3 = _person2->add_phone();
- _phone3->set_number("+8613996398667");
- _phone3->set_type(cn::vicky::model::seri::MOBILE);
-
- // 建立角色中的一個電話號碼:2
- cn::vicky::model::seri::PhoneNumber* _phone4 = _person2->add_phone();
- _phone4->set_number("02882334717");
- _phone4->set_type(cn::vicky::model::seri::WORK);
-
-
- // 持久化:
- // std::fstream out("User.pb", std::ios::out | std::ios::binary | std::ios::trunc);
- // u.SerializeToOstream(&out);
- // out.close();
-
- // 對象化:
- cn::vicky::model::seri::User u2;
- std::fstream in("User.pb", std::ios::in | std::ios::binary);
- if (!u2.ParseFromIstream(&in)) {
- std::cerr << "Failed to parse User.pb." << std::endl;
- exit(1);
- }
-
- std::cout << u2.id() << std::endl;
- std::cout << u2.username() << std::endl;
- std::cout << u2.password() << std::endl;
- std::cout << u2.email() << std::endl;
-
- std::cout << "---------------------------" << std::endl;
- for(int i = 0;i < u2.person_size();i++) {
- cn::vicky::model::seri::Person* p = u2.mutable_person(i);
- std::cout << p->id() << std::endl;
- std::cout << p->name() << std::endl;
- for (int j = 0;j < p->phone_size();j++) {
- cn::vicky::model::seri::PhoneNumber* phone = p->mutable_phone(j);
- std::cout << phone->number() << std::endl;
- }
- std::cout << "---------------------------" << std::endl;
- }
- return 0;
- }
須要 -lpthread -lprotobuf (protobuf已經被加載到了/usr/lib)
執行後,會生成:User.pb,存儲的二進制文件.能夠直接打開看看.
以上,咱們使用了protobuf完成c++下的對象序列化以及反序列化.這裏咱們要描述一下protobuf的優點了.
那就是protobuf性能高效,他的序列化速度比java自身的序列化還快數倍,並且支持3種語言對象的轉換.以往,在C++中序列化的對象,好比用boost serialization持久化的對象,沒法用java展開,即使使用jni技術,這也是很是麻煩的事.如今咱們有protobuf了.
運行: protoc -I=./ --java_out=./ model.proto 將生成對應的Java類
咱們能夠用Maven創建一個Java工程.須要protobuf的java依賴庫:
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <groupId>cn.vicky</groupId>
- <artifactId>google_protobuf_01_java</artifactId>
- <version>1.0-SNAPSHOT</version>
- <packaging>jar</packaging>
-
- <name>google_protobuf_01_java</name>
- <url>http://maven.apache.org</url>
-
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>com.google.protobuf</groupId>
- <artifactId>protobuf-java</artifactId>
- <version>2.4.1</version>
- </dependency>
- </dependencies>
- </project>
編寫Test.java
- package cn.vicky.model.seri;
-
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
-
- /**
- *
- * @author Vicky.H
- */
- public class Test {
-
- public static void main(String args[]) throws FileNotFoundException, IOException {
- File file = new File("User.pb");
- InputStream is = new FileInputStream(file);
- Model.User user = Model.User.parseFrom(is);
- System.out.println(user.getId());
- System.out.println(user.getUsername());
- System.out.println(user.getPassword());
- System.out.println(user.getEmail());
- System.out.println("-------------------");
- for (Model.Person person : user.getPersonList()) {
- System.out.println(person.getId());
- System.out.println(person.getName());
- for (Model.PhoneNumber phone : person.getPhoneList()) {
- System.out.println(phone.getNumber());
- }
- System.out.println("-------------------");
- }
- is.close();
- }
- }
運行:
1
Jack
123456
289997171@qq.com
---------------------------
1
P1
+8613618074943
02882334717
---------------------------
2
P2
+8613996398667
02882334717
---------------------------
運行 SUCCESSFUL (總時間: 594ms)
OK.以上咱們完成了probuf在C++,Java的使用.很是強力是否是!!
設計思想:
在POJO中,protobuf生成的類,處於PO狀態,並且這個生成的類,咱們最好不要作任何修改或太大的修改,那麼,這個時候,咱們能夠經過C++友元類的方式,爲PO添加一個JO類.將數據結構算法分離,也就是說,PO是數據,JO放算法!!!
與數據庫的結合:
mysql oracle 能夠很輕鬆的存儲,讀取二進制.還有一點,那就是經過這種方式,咱們能夠很是簡單的將C++的對象,持久化的redis之類內存數據庫了.
附:
model.proto也能夠這樣定義,不過,本人認爲,上面的更好,這裏僅供參考,採用什麼樣的方式,生成的類的結構也不太同樣.
- package cn.vicky.model.seri;
-
- message User {
- required int32 id = 1; // 主鍵,惟一
- required string username = 2; // 賬號
- required string password = 3; // 密碼
- optional string email = 4; // 郵箱(可選)
-
- message Person {
- required int32 id = 1; // 主鍵,惟一
- required string name = 2; // 角色名字
-
- // 枚舉類型
- enum PhoneType {
- MOBILE = 0;
- HOME = 1;
- WORK = 2;
- }
-
- message PhoneNumber {
- required string number = 1;
- optional PhoneType type = 2 [default = HOME];
- }
-
- repeated PhoneNumber phone = 3; // 電話號碼(能夠重複)
- }
-
- repeated Person person = 5; // 帳戶擁有的角色(能夠重複)
- }