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

1.下载安装:

google protocol buffer 的官网地址是:http://code.google.com/p/protobuf/

        建议下载稳定版本:protobuf-2.4.1  linux下载protobuf-2.4.1.tar.bz2   windows下载protobuf-2.4.1.zip


这里以linux下安装为实例:

tar -xvf protobuf-2.4.1.tar.bz2

cd protobuf-2.4.1

./configure --prefix=/usr/local/protobuf-2.4.1

make

make install

2.使用protobuf

查看编译生成的目录

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:  [email protected] 
  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("[email protected]");  
  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
[email protected]
---------------------------
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. }  

你可能感兴趣的:(google protocol buffer (C++,Java序列化使用实例))