前言
protobuf是什么的测暗?
Protocol Buffer是一種用于序列化數(shù)據(jù)的協(xié)議央串。可以用來通信傳輸碗啄,數(shù)據(jù)傳輸?shù)戎屎汀?梢杂脕砣〈鷍son稚字,xml等饲宿。
為什么要用protobuf?
解析速度快胆描,生成的消息體積小瘫想,語法簡潔明了,支持多種語言( C++袄友、C#殿托、Go、Java剧蚣、Python支竹、JavaScript等等)
正如下圖,protobuf會把數(shù)據(jù)的體積壓縮到盡可能的小鸠按。
官方的api
protobuf由谷歌開發(fā)礼搁,谷歌內(nèi)部都在使用,所以放心地使用吧目尖。 這是github上的地址 https://github.com/google/protobuf
前期準備
1馒吴,安裝maven庫
到官網(wǎng)下載對應(yīng)的maven。
下載后是一個壓縮包瑟曲,解壓饮戳。然后對應(yīng)的bin目錄(比如 C:\Program Files\apache-maven-3.3.9\bin)配置到環(huán)境變量PATH中就好了。
配置好環(huán)境變量之后洞拨,到命令行中扯罐,輸入
mvn -v
會看到類似這樣的輸出,就證明你的maven已經(jīng)配置成功了烦衣。
Apache Maven 3.3.3 (7994120775791599e205a5524ec3e0dfe41d4a06; 2015-04-22T04:57:37-07:00)
Maven home: /opt/apache-maven-3.3.3
Java version: 1.8.0_45, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.8.5", arch: "x86_64", family: "mac"
2歹河, 配置protoc的環(huán)境變量
- 從這個地址下載protoc-3.2.0-win32.zip文件。
- 解壓花吟。
- 把里面的protoc.exe配置到環(huán)境變量中去秸歧。
3,生成jar包
- 我們需要生成jar包衅澈,放到Android項目的lib中键菱,項目才能使用protobuf。
同樣也是這個地址矾麻。這次需要下載protobuf-java-3.2.0.zip纱耻。如果你使用的是其他語言芭梯,就下載不同語言對應(yīng)的文件即可险耀。
注意:步驟2和步驟3中用到的包的版本號要一致弄喘。
- 解壓protobuf-java-3.2.0.zip。
- 把步驟2中得到的protoc.ext放到protobuf-java-3.2.0/src中
- 用命令行甩牺,cd到protobuf-java-3.2.0/java目錄下
- 輸入指令
mvn test
- 繼續(xù)輸入指令
mvn package
運行成功后蘑志,jar包就會出現(xiàn)在protobuf-java-3.2.0/java/core/target目錄下了。
編寫proto文件
這是一個簡單的proto文件贬派。
syntax = "proto3";
message SearchRequest {
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
}
- 語法是不是很簡單
- syntax = "proto3";表示語言的版本為proto3急但,如果不定義,系統(tǒng)就默認為proto2
- SearchRequest定義了一個信息搞乏。里面存放著三個變量波桩。一個string類型,兩個int類型请敦。
- 可以看到镐躲,三個變量后面分別跟著1,2,3。這不是變量的值侍筛,這是一個tag萤皂,標(biāo)志這個標(biāo)量在二進制格式里的位置。因為1-15只需要一個byte匣椰,而16到2047需要兩個byte裆熙,所以我們需要把常用的變量放到1-15中去。而tag的值可以從1定義到536,870,911禽笑,除了19000到19999入录。
- 具體的所有數(shù)據(jù)類型,可以到官網(wǎng)看佳镜。
加上稍微復(fù)雜一點的proto文件
syntax = "proto3";
message SearchRequest {
//這是一個枚舉
enum Type{
FAST_SEARCH = 0;
SLOW_SEARCH = 1;
NOTHING = 3;
}
string query = 1;
int32 page_number = 2;
int32 result_per_page = 3;
Type type = 4;//上面定義的枚舉僚稿,這里就可以用了
bytes data = 5;//這是一個bytes類型的數(shù)據(jù)拌屏∽辏可以用來存放另外一個message忍坷。
}
編譯
把protoc編譯成java文件
官方的語法是這樣的憎兽。
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto
我自己的做法比較簡單一點屹耐。
cd到proto文件的目錄燃领,然后輸入
protoc --java_out=ProtoBuffer prototest.proto
- ProtoBufferjava文件生成的文件夾颗味。
- prototest.proto是proto文件舔亭。
- 如果是生成其他類型的文件脖律,只需要把java_out替換成對應(yīng)的cpp_out,csharp_out等即可谢肾。指令可以通過輸入protoc -help瀏覽。
在java中使用
首先小泉,需要把上面得到的jar包放到lib里面芦疏。把得到的java文件放到項目中冕杠。
通過以下方式生成一個對象,是的酸茴,如果你沒有寫入任何變量分预。那所有變量的值都是默認值。
Prototest2.SearchRequest searchRequest = Prototest2
.SearchRequest.newBuilder().build();
然而你只能在生成的時候賦值薪捍。笼痹。
Prototest2.SearchRequest searchRequest = Prototest2
.SearchRequest.newBuilder()
.setQuery("hhh")
.setPageNumber(2)
.setData(book.toByteString())//book是另外一個proto對象
.setType(Prototest2.SearchRequest.Type.SLOW_SEARCH)//設(shè)置枚舉類型
.build();
上面可以看到,我們可以通過toByteString()把proto對象轉(zhuǎn)成byteString類型的數(shù)據(jù)酪穿。而對應(yīng)的凳干,可以把byteString數(shù)據(jù)通過parseFrom轉(zhuǎn)化為proto對象。
Prototest3.Book book1 = Prototest3.Book.parseFrom(searchRequest.getData());
寫到流中
通過writeTo方法被济,把消息寫入輸出流中
writeTo(OutputStream output)
這個方法只是writeTo(CodedOutputStream)方法的包裝方法救赐。同樣地,這個方法不會flush或者close流只磷。
注意:brotobuf不會自限制(?)经磅,所以如果你在這個消息之后又在同一個流里面wirte了其他的信息,那你必須做一些操作去確定哪一部分是brotobuf喳瓣。例如馋贤,你可以在這個消息之前發(fā)送數(shù)據(jù)的大小,然后確認這個消息到什么地方為止畏陕∨渑遥或者,直接使用writeDelimitedTo(OutputStream)惠毁。
writeDelimitedTo(OutputStream)
和writeTo(OutputStream output)一樣犹芹,不過會用varint的方法在數(shù)據(jù)之前寫一下數(shù)據(jù)的大小。這就允許在同一個流里面寫更多數(shù)據(jù)了鞠绰。Use MessageLite.Builder.mergeDelimitedFrom(InputStream) (or the static method YourMessageType.parseDelimitedFrom(InputStream)) to parse messages written by this method.
從流中讀取
Prototest2.SearchRequest.parseDelimitedFrom(inputStream);