Protocol Buffers的基础说明和使用

       我们開始须要使用protobuf的原因是,在处理OJ的contest模块的时候,碰到一个问题就是生成contestRank的时候。须要存储非常多信息。

假设我们採用model存储的话,那么一方面兴许假设继续加入其它信息的话改动会灰常麻烦。另一方面就是实现比較复杂。由于对于rank来说,每一条rank的主键首先是UserID,其次存储的基本信息有AC数,题目AC情况,罚时等等,当中题目AC情况又包含以题目ID为主键,属性(是否AC。AC时间。罚时。这道题目的提交统计)。而每一道题目的提交统计又是一个submit实体,这种话。就会有多级嵌套存在。

假设兴许加入的话会很多其它。

另一个原因就是存储也不方便,逻辑构思不是非常明白。须要注意保存各种信息。实现复杂。

protobuf的主要机理是把存储的信息序列化为一个字符串存储。须要信息的时候又能够逆序列化把原始信息还原出来。并且能够实现多级嵌套的属性。所以就尝试使用这个来解决rank的存储(/ □ )

1:protobuf是什么?

 好吧,这个有百科,see see:protocolbuffer是google 的一种数据交换的格式,它独立于语言,独立于平台。google 提供了三种语言的实现:java、c++ 和 python。每一种实现都包括了对应语言的编译器以及库文件。

因为它是一种二进制的格式,比使用 xml 进行数据交换快很多。能够把它用于分布式应用之间的数据通信或者异构环境下的数据交换。

作为一种效率和兼容性都非常优秀的二进制传输数据格式,能够用于诸如网络传输、配置文件、数据存储等诸多领域。

简单地说,就是把某种数据结构的信息,以某种格式保存起来。

主要用于数据存储、传输协议格式等场合

2:下载安装:

地址:http://code.google.com/p/protobuf/downloads/list

安装:

 tar -xzf protobuf-2.1.0.tar.gz 
 cd protobuf-2.1.0 
 ./configure  
 make 
 make check 
 make install

3:使用建立

网上有各种样例,比方简单的book的书写等等都能够用来练习操作

首先,首先我们须要编写一个 proto 文件,定义我们程序中须要处理的结构化数据,在 protobuf 的术语中,结构

化数据被称为 Message。比如:

package contest_submit;
 message ContestSubmit {
   required int32 id = 1;
   required int64 timestamp = 2;
 }

上述样例中id是int32的,timestamp是int64的。required代表这个是必须的,有点像数据库里的not null,另一

种就是optional。就可以选的。

编译.proto文件,命令例如以下:

protoc -I=./ --python_out=./ ./*.proto

代表的意思是输入的.proto文件在当前文件夹,输出生成的编译文件到当前文件夹,源文件是全部以.proto结尾的文件

网上完整的格式是:

如果您的 proto 文件存放在 $SRC_DIR 以下,您也想把生成的文件放在同一个文件夹下,则能够使用例如以下命令:
 protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/文件明.proto

编译完毕之后会生成 contest_submit_pb2.py文件(对于上面的样例来说)

当然,protobuf也是能够嵌套的。即能够在一个类中声明还有一个类的对象,比如,rank的实现:

package contest_rank;
 message Submit {
   optional string status = 1;
   optional string date_time = 2;
   optional string runID = 3;
 }
 
 message Problem {
   optional int32 problemID = 1;
   repeated Submit submit = 2;
   optional int32 acindex = 3;
   optional int32 totalindex = 4;
   optional int32 time = 5;
   optional int32 FB = 6;
 }
 
 message Rank {
   optional string userID = 1;
   optional string contestID = 2;
   repeated Problem problem = 3;
   optional int32 penalty = 4;
   optional int32 ac = 5;
   optional int32 total = 6;
 }
 
 message ContestRankList {
   optional string contestID = 1;
   repeated Rank rank = 2;
 }
这种话。就能够实现我们前面的需求即多级信息嵌套了。

使用:

首先,要记得加载头文件from 目录.proto import rank_pb2

对于实现rank的存储的时候。首先声明一个rank类,以便兴许对数据的处理

class Rank():
   class Problem():
     class Submit():
       def __init__(self, runID = "", status="", date_time=""):
         self.status = status
         self.date_time = date_time
         self.runID = runID
 
     def __init__(self, problemID):
       self.problemID = problemID
       self.submit_list = []
       self.acindex = 0
       self.totalindex = 0
       self.time = 0
       self.FB = 0
 
     def add_submit(self, submit):
       self.submit_list.append(submit)
 
   def __init__(self, userID, contestID):
     self.userID = userID
     self.contestID = contestID
     self.problem_list = {}
     self.ac = 0
     self.penalty = 0
     self.total = 0
 
当我们得到rank_list的时候(rank_list是一个存放rank的字典),首先声明一个proto的载体:

contest_rank_list = rank_pb2.ContestRankList()
然后填充信息,比方先把比赛的ID增加,即contest_rank_list.contestID = contestID。

然后依照protobuf的结构,依

次把须要的信息填入。

对于嵌套的实体来说,每次声明的时候能够使用add()方法,比方在一个比赛中,会有多个用户

的rank信息存在。所以依照用户ID来加入信息:

rank_proto = contest_rank_list.rank.add()
rank.load_data_to_proto(rank_proto)
当中的load_data_to_proto是rank类的一个方法。内容就是把信息增加到protobuf里面而已:

def load_data_to_proto(self, rank):
     rank.userID = self.userID
     rank.contestID = self.contestID
     rank.ac = self.ac
     rank.penalty = self.penalty
     rank.total = self.total
 
     for problemID in self.problem_list:
       problem = self.problem_list[problemID]
       p = rank.problem.add()
       p.problemID = problem.problemID
       p.acindex = problem.acindex
       p.totalindex = problem.totalindex
       p.time = problem.time
       p.FB = problem.FB
       for submit in problem.submit_list:
         s = p.submit.add()
         s.status = submit.status
         s.date_time = submit.date_time
         s.runID = submit.runID
     return rank
 
这样我们就把数据存入了我们声明的protobuf里面了。然后就是存储的时候序列化。比方我们存储到SSDB里面即:

ssdb_api.SetContestRankListProto(contestID, contest_rank_list.SerializeToString())

至此。信息已经存入数据库。那么接下来就是怎样读出了:

对于得到我们存储的rank信息来说。即:

 contest_rank_list = ssdb_api.GetContestRankListProto(contest_id)
 rank_list = rank_pb2.ContestRankList()
 rank_list.ParseFromString(contest_rank_list)
即,再次声明一个protobuf的对象,然后逆序列化。就得到了我们须要的信息。简单吧(/ □ )。

后面须要的数据。就用父名.子名訪问就可以。






原文地址:https://www.cnblogs.com/jzssuanfa/p/7067165.html