google protocol buffer (C++,Java序列化使用實例)

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

[cpp]  view plain copy
  1. 數據結構體:  
  2.     message message_name{message_body;}  
  3.     message_body格式:  
  4.         例如required int32 query = 1[defaut=10];  
  5.         形式爲:rule type name = value[other_rule];  
  6. 規則:  
  7.     required表示必須具備該值域;  
  8.     optional表示可選的值域;  
  9.     repeated表示可重複的值域(即>=0);  
  10.     其中requered/optional是經常使用rule,而repeated則不經常使用同時由於是歷史遺留現使用repeated int32 samples=4[packed=true];形式;  
  11.   
  12. value值:  
  13.     value值最小爲1,是底層編碼時使用其中1-15佔一位,>15則會佔多位;  
  14.     不一樣的message中的value值互不干擾,常以1開始計數。  
  15.   
  16. 數據類型之基本類型:  
  17. .proto Type             C++ Type            Java Type   
  18. double                  double              double   
  19. float                   float               float   
  20. int32                   int32               int   
  21. int64                   int64               long   
  22. uint32                  uint32              int   
  23. uint64                  uint64              long   
  24. sint32                  int32               int   
  25. sint64                  int64               long   
  26. fixed32                 uint32              int   
  27. fixed64                 uint64              long   
  28. sfixed32                int32               int   
  29. sfixed64                int64               long   
  30. bool                    bool                boolean   
  31. string                  string              String   
  32. bytes                   string              ByteString   
  33.   
  34. 數據類型之複雜類型:  
  35.     複雜類型主要包括:枚舉,其餘message,groups等。  
  36.     枚舉定義例如:enum Corpus{WEB=0;LOCAL=1}  
  37.         枚舉定義在message中。  
  38.         能夠使用其餘message做爲類型來定義成員。  
  39.         groups個人理解有些像C++中的union結構。  
  40.   
  41. 嵌套定義:  
  42.     能夠嵌套定義message結構,而嵌套定義的message被其餘message做爲成員類型時須要形式爲outmessage.inmessage形式。  
  43.   
  44. 包結構:  
  45.     定義形式:package foo.bar;  
  46.     對應C++中則生成兩個命名空間foo和bar,且bar定義在foo中;  
  47.     能夠經過import "myproject/other_protos.proto";來引入.proto文件;  
  48.     引用其餘package中message時須要完整的package路徑;  
  49.   
  50. Services:  
  51.     主要用於RPC系統中,在.proto中定義接口;  
  52.     定義形式如例子:  
  53.     service SearchService {  
  54.         rpc Search(SearchRequest) return (SearchResponse);  
  55.     }  
  56.   
  57. .proto文件編譯:  
  58.     格式:  
  59.         protoc -–proto_path=(.proto文件路徑) -–cpp_out=(.cc .java生成文件路徑) (.proto文件路徑)/?.proto  
  60.         -–proto_path  簡化爲:  --I  
  61.         其中可根據須要更改:cpp_out選項爲java_out/python_out。  
  62.     例子:  
  63.         protoc -I=./ --cpp_out=./ model.proto  


咱們拿個例子:

創建model.proto

[cpp]  view plain copy
  1. package cn.vicky.model.seri;  
  2.   
  3. message User {  
  4.     required int32 id = 1; // 主鍵,惟一  
  5.     required string username = 2; // 賬號  
  6.     required string password = 3; // 密碼  
  7.     optional string email = 4; // 郵箱(可選)  
  8.     repeated Person person = 5; // 帳戶擁有的角色(能夠重複)  
  9. }  
  10.   
  11. message Person {   
  12.     required int32 id = 1; // 主鍵,惟一  
  13.     required string name = 2; // 角色名字  
  14.   
  15.     repeated PhoneNumber phone = 3; // 電話號碼(能夠重複)  
  16. }   
  17.   
  18. // 枚舉類型  
  19. enum PhoneType {   
  20.     MOBILE = 0;   
  21.     HOME = 1;   
  22.     WORK = 2;   
  23. }   
  24.   
  25. message PhoneNumber {   
  26.     required string number = 1;   
  27.     optional PhoneType type = 2 [default = HOME];   
  28. }   

protoc -I=./ --cpp_out=./ model.proto

將生成對應的model.pb.h  model.pb.cc

使用:

編寫main.cpp

[cpp]  view plain copy
  1. /*  
  2.  * File:   main.cpp 
  3.  * Author: Vicky.H 
  4.  * Email:  eclipser@163.com 
  5.  */  
  6. #include <iostream>  
  7. #include <fstream>  
  8. #include "model.pb.h"  
  9.   
  10. /* 
  11.  *  
  12.  */  
  13. int main(void) {  
  14.   
  15.     // 建立User對象  
  16.     cn::vicky::model::seri::User u;  
  17.     u.set_id(1);  
  18.     u.set_username("Jack");  
  19.     u.set_password("123456");  
  20.     u.set_email("289997171@qq.com");  
  21.   
  22.     // 建立User中的一個角色  
  23.     cn::vicky::model::seri::Person* _person1 = u.add_person();  
  24.     _person1->set_id(1);  
  25.     _person1->set_name("P1");  
  26.   
  27.     // 建立角色中的一個電話號碼:1  
  28.     cn::vicky::model::seri::PhoneNumber* _phone1 = _person1->add_phone();  
  29.     _phone1->set_number("+8613618074943");  
  30.     _phone1->set_type(cn::vicky::model::seri::MOBILE);  
  31.   
  32.     // 建立角色中的一個電話號碼:2  
  33.     cn::vicky::model::seri::PhoneNumber* _phone2 = _person1->add_phone();  
  34.     _phone2->set_number("02882334717");  
  35.     _phone2->set_type(cn::vicky::model::seri::WORK);  
  36.   
  37.   
  38.     // 建立User中的一個角色  
  39.     cn::vicky::model::seri::Person* _person2 = u.add_person();  
  40.     _person2->set_id(2);  
  41.     _person2->set_name("P2");  
  42.   
  43.     // 建立角色中的一個電話號碼:1  
  44.     cn::vicky::model::seri::PhoneNumber* _phone3 = _person2->add_phone();  
  45.     _phone3->set_number("+8613996398667");  
  46.     _phone3->set_type(cn::vicky::model::seri::MOBILE);  
  47.   
  48.     // 建立角色中的一個電話號碼:2  
  49.     cn::vicky::model::seri::PhoneNumber* _phone4 = _person2->add_phone();  
  50.     _phone4->set_number("02882334717");  
  51.     _phone4->set_type(cn::vicky::model::seri::WORK);  
  52.   
  53.   
  54.     // 持久化:  
  55. //    std::fstream out("User.pb", std::ios::out | std::ios::binary | std::ios::trunc);  
  56. //    u.SerializeToOstream(&out);  
  57. //    out.close();  
  58.   
  59.     // 對象化:  
  60.     cn::vicky::model::seri::User u2;  
  61.     std::fstream in("User.pb", std::ios::in | std::ios::binary);  
  62.     if (!u2.ParseFromIstream(&in)) {  
  63.         std::cerr << "Failed to parse User.pb." << std::endl;  
  64.         exit(1);  
  65.     }  
  66.       
  67.     std::cout << u2.id() << std::endl;  
  68.     std::cout << u2.username() << std::endl;  
  69.     std::cout << u2.password() << std::endl;  
  70.     std::cout << u2.email() << std::endl;  
  71.   
  72.     std::cout << "---------------------------" << std::endl;  
  73.     for(int i = 0;i < u2.person_size();i++) {  
  74.         cn::vicky::model::seri::Person* p = u2.mutable_person(i);  
  75.         std::cout << p->id() << std::endl;  
  76.         std::cout << p->name() << std::endl;  
  77.         for (int j = 0;j < p->phone_size();j++) {  
  78.             cn::vicky::model::seri::PhoneNumber* phone = p->mutable_phone(j);  
  79.             std::cout << phone->number() << std::endl;  
  80.         }  
  81.         std::cout << "---------------------------" << std::endl;  
  82.     }  
  83.     return 0;  
  84. }  


須要 -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依賴庫:

[html]  view plain copy
  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.     <modelVersion>4.0.0</modelVersion>  
  4.   
  5.     <groupId>cn.vicky</groupId>  
  6.     <artifactId>google_protobuf_01_java</artifactId>  
  7.     <version>1.0-SNAPSHOT</version>  
  8.     <packaging>jar</packaging>  
  9.   
  10.     <name>google_protobuf_01_java</name>  
  11.     <url>http://maven.apache.org</url>  
  12.   
  13.     <properties>  
  14.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  15.     </properties>  
  16.   
  17.     <dependencies>  
  18.         <dependency>  
  19.             <groupId>com.google.protobuf</groupId>  
  20.             <artifactId>protobuf-java</artifactId>  
  21.             <version>2.4.1</version>  
  22.         </dependency>  
  23.     </dependencies>  
  24. </project>  

編寫Test.java
[java]  view plain copy
  1. package cn.vicky.model.seri;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8.   
  9. /** 
  10.  * 
  11.  * @author Vicky.H 
  12.  */  
  13. public class Test {  
  14.   
  15.     public static void main(String args[]) throws FileNotFoundException, IOException {  
  16.         File file = new File("User.pb");  
  17.         InputStream is = new FileInputStream(file);  
  18.         Model.User user = Model.User.parseFrom(is);  
  19.         System.out.println(user.getId());  
  20.         System.out.println(user.getUsername());  
  21.         System.out.println(user.getPassword());  
  22.         System.out.println(user.getEmail());  
  23.         System.out.println("-------------------");  
  24.         for (Model.Person person : user.getPersonList()) {  
  25.             System.out.println(person.getId());  
  26.             System.out.println(person.getName());  
  27.             for (Model.PhoneNumber phone : person.getPhoneList()) {  
  28.                 System.out.println(phone.getNumber());  
  29.             }  
  30.             System.out.println("-------------------");  
  31.         }  
  32.         is.close();  
  33.     }  
  34. }  

運行:

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也能夠這樣定義,不過,本人認爲,上面的更好,這裏僅供參考,採用什麼樣的方式,生成的類的結構也不太同樣.

[cpp]  view plain copy
  1. package cn.vicky.model.seri;  
  2.   
  3. message User {  
  4.     required int32 id = 1; // 主鍵,惟一  
  5.     required string username = 2; // 賬號  
  6.     required string password = 3; // 密碼  
  7.     optional string email = 4; // 郵箱(可選)  
  8.   
  9.     message Person {   
  10.         required int32 id = 1; // 主鍵,惟一  
  11.         required string name = 2; // 角色名字  
  12.   
  13.         // 枚舉類型  
  14.         enum PhoneType {   
  15.             MOBILE = 0;   
  16.             HOME = 1;   
  17.             WORK = 2;   
  18.         }   
  19.   
  20.         message PhoneNumber {   
  21.             required string number = 1;   
  22.             optional PhoneType type = 2 [default = HOME];   
  23.         }   
  24.   
  25.         repeated PhoneNumber phone = 3; // 電話號碼(能夠重複)  
  26.     }   
  27.   
  28.     repeated Person person = 5; // 帳戶擁有的角色(能夠重複)  
  29. }  
相關文章
相關標籤/搜索