因爲面試中騰訊,京東等大公司都有被考到protobuf的知識,我居然只知道xml,json效率比protobuf大大降低,碎研究了下它希望對大家有所幫助!
protobuf的介紹
一條消息數據,用protobuf序列化後的大小是json的10分之一,xml格式的20分之一,是二進制序列化的10分之一,總體看來ProtoBuf的優勢還是很明顯的。
protobuf是google提供的一個開源序列化框架,類似於XML,JSON這樣的數據表示語言,詳情訪問protobuf的google官方網站。
protobuf在google中是一個比較核心的基礎庫,作爲分佈式運算涉及到大量的不同業務消息的傳遞,如何高效簡潔的表示、操作這些業務消息在google這樣的大規模應用中是至關重要的。而protobuf這樣的庫正好是在效率、數據大小、易用性之間取得了很好的平衡。
protobuf簡單總結如下幾點:
1.靈活(方便接口更新)、高效(效率經過google的優化,傳輸效率比普通的XML等高很多);
2.易於使用;開發人員通過按照一定的語法定義結構化的消息格式,然後送給命令行工具,工具將自動生成相關的類,可以支持java、c++、python等語言環境。通過將這些類包含在項目中,可以很輕鬆的調用相關方法來完成業務消息的序列化與反序列化工作。
3.語言支持;原生支持c++,java,python
數據交互xml、json、protobuf格式比較
1、json: 一般的web項目中,最流行的主要還是json。因爲瀏覽器對於json數據支持非常好,有很多內建的函數支持。
2、xml: 在webservice中應用最爲廣泛,但是相比於json,它的數據更加冗餘,因爲需要成對的閉合標籤。json使用了鍵值對的方式,不僅壓縮了一定的數據空間,同時也具有可讀性。
3、protobuf:是後起之秀,是谷歌開源的一種數據格式,適合高性能,對響應速度有要求的數據傳輸場景。因爲profobuf是二進制數據格式,需要編碼和解碼。數據本身不具有可讀性。因此只能反序列化之後得到真正可讀的數據。
相對於其它protobuf更具有優勢
1:序列化後體積相比Json和XML很小,適合網絡傳輸
2:支持跨平臺多語言
3:消息格式升級和兼容性還不錯
4:序列化反序列化速度很快,快於Json的處理速速
比較詳細的介紹
https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/index.html
上述講了什麼是protobuf以及優點是什麼,廢話不多說下面我將介紹protobuf具體事例
環境介紹:Linux ubuntu 4.4.0-141-generic #167-Ubuntu SMP Wed Dec 5 10:38:08 UTC 2018 i686 i686 i686 GNU/Linux
1、protobuf安裝
apt-get install libprotobuf-dev
2、文件定義test.proto:
mkdir protobuf-test
vi test.proto
message student{
required string name = 1; //姓名
required int32 age = 2; //年齡
optional string sex = 3; //性別
}
//類
message person{
repeated student member = 1; //成員
}
執行命令:protoc ./test.proto --cpp_out=./ 會在當前目錄生成兩個文件用於序列化數據
3、序列化數據
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h>
#include <fstream>
#include <cstdio>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include "test.pb.h"
using namespace std;
int main(int argc, char** argv)
{
if (argc <2){
printf("programe savefile\n");
exit(1);
}
person c;
//添加學生
student* t = c.add_member();
t->set_name("Toy");
t->set_age(21);
t->set_sex("boy");
t = c.add_member();
t->set_name("jack");
t->set_age(25);
t->set_sex("boy");
t = c.add_member();
t->set_name("lili");
t->set_age(20);
t->set_sex("girl");
//首先將protobuf輸出到一個string中
std::string p;
google::protobuf::TextFormat::PrintToString(c,&p);
//輸出到文件中
ofstream fout;
fout.open(argv[1], ios::out| ios_base::ate);
if (!fout.is_open()){
fprintf(stderr, "open %s fail\n", argv[1]);
return -1;
}
fout <<p<<endl;
fout.flush();
fout.close();
return 0;
}
編譯:g++ proto-write.cc test.pb.cc -lprotobuf -o proto-write
結果:
4、讀取解析
#include "test.pb.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h>
#include <fstream>
#include <cstdio>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
using namespace std;
int main(int argc, char** argv)
{
if (argc <2){
printf("programe reloadfile\n");
exit(1);
}
person c;
int fileDescriptor = open(argv[1], O_RDONLY);
if( fileDescriptor < 0 ){
return -1;
}
google::protobuf::io::FileInputStream fileInput(fileDescriptor);
fileInput.SetCloseOnDelete( true );
if (!google::protobuf::TextFormat::Parse(&fileInput, &c)){
return -2;
}
cout<<"student number:"<<c.member_size()<<endl;
for (int i = 0 ; i < c.member_size(); i++){
cout <<"student name:"<<c.member(i).name()<<endl;
cout <<"student age:" << c.member(i).age()<<endl;
cout <<"student sex:" << c.member(i).sex() <<endl;
}
return 0;
}
編譯:
g++ proto-read.cc test.pb.cc -lprotobuf -o proto-read
結果: