日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

protobuf中 repeated[Ptr]Field的序列化

發布時間:2025/3/21 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 protobuf中 repeated[Ptr]Field的序列化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
message Test1 {required int32 a = 1; }Test1 t1; t1.set_a(150); 序列化之后的結果是 08 96 01。 其中08 >>3 == 1是a的字段序號; 08的低3位(0)是類型varint(int32)96 01 = 1001 0110 0000 0001→ 000 0001 ++ 001 0110 (drop the msb and reverse the groups of 7 bits)→ 10010110→ 2 + 4 + 16 + 128 = 150message Test3 { required Test1 c = 3;}Test3 t3; t3.mutable_c()->set_a(150); 序列化之后的結果是1a 03 08 96 01 同上。 1a >>3 == 3是c的字段序號; 1a的低3位(2)類型是length-delimited(embeded message)。 第二個字節的03 表示后續 08 96 01的字節個數 08 96 01就是c序列化的結果。從這里可以很明顯的看出, 在序列化結構體時, 是不包含結構體本身的任何信息的。 那么對于repeated如何序列化? pack? 從google看, 需要使用protobuf的cimplementation:protobuf-c, 且只對primitive有效。見http://code.google.com/p/protobuf-c/wiki/Examples此前, message Test {repeated int32 a = 1; }string s; ....OutputCodedStream ss(...s...); repeatedPtrField<Test> tt;....//假設tt.size() == 3 for(int i= 0; i < tt.size(); i++)tt.SerializeToCodedStream(&ss);////多個Test對象這樣序列化時, 在stream中是沒有邊界的, 再ParseFrom的時候就會出問題了。。。之后從s 反序列化時, 只能得到一個Test對象, 且tt中3個Test中的a數組的值都放到了這個唯一的Test對象中。。。。!!!!因此,我這里不得不使用較原始的方法: template <class T> bool RepeatedPtrSerialize(const google::protobuf::RepeatedPtrField<T> &tmp, string &s) { //特別強調, 在下述語句中, 不能以任何方式訪問s, 否則得到的結果就不正確。google::protobuf::io::StringOutputStream ss(&s);google::protobuf::io::CodedOutputStream codedOutput(&ss);for(int i = 0 ;i < tmp.size(); i++){ codedOutput.WriteLittleEndian32(tmp.Get(i).ByteSize());tmp.Get(i).SerializeToCodedStream(&codedOutput);} return true; }template <class T> bool RepeatedPtrParseFrom(google::protobuf::RepeatedPtrField<T> &tmp, const string &s) {stringstream sss(s);google::protobuf::io::IstreamInputStream ssi(&sss);google::protobuf::io::CodedInputStream codedOutputi(&ssi);while(!codedOutputi.ExpectAtEnd()){unsigned int len = 0;string s;if(!codedOutputi.ReadLittleEndian32(&len)) break;if(!codedOutputi.ReadString(&s, len)) break;T *obj = tmp.Add();obj->ParseFromString(s);從這里再構造T。。。}return true; }https://developers.google.com/protocol-buffers/docs/encoding序列化時, 按<key, value>的形式存儲; 多個字段的話順序存儲; 字段間無順序關系。key: 由字段順序號 + 字段類型。 field_num << 3 | wire_type。 字段類型如下:Type Meaning Used For 0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum 1 64-bit fixed64, sfixed64, double 2 Length-delimited string, bytes, embedded messages, packed(only support repeated primitive fields) repeated fields 3 Start group groups (deprecated) 4 End group groups (deprecated) 5 32-bit fixed32, sfixed32, float關于varint, 使用可變長度編碼上述類型。小于128的無符號, 用1個字節就行, 比uint32節約3個字節, 比uint64節約5個字節。多個字節表示1個數時,前面的字節最高位都為1; 最后一個字節的最高位為0,表示是最后一個字節了。但是對于負數,不太管用,因為最高位的符號位為1。 因此對于sint32, sint64使用ZigZag壓縮。以int32為例, ZigZag將區間[-2^31, 2^31 - 1] 映射為[0, 2^32 - 1]. 映射后的值 n 如果是偶數, 則原來的數就是n/2, 否則就是 -(n+1)/2。Zigzag(n) = (n << 1) ^ (n >> 31), n為sint32時Zigzag(n) = (n << 1) ^ (n >> 63), n為sint64時下表是一個比較直觀的映射表,這樣映射后再進行編碼的好處就是絕對值比較小的負數序列化后的結果占的Bytes數也會比較少。 Signed Original Encoded As 0 0 -1 1 1 2 -2 3 2 4 -3 5 … … 2147483647 4294967294 -2147483648 4294967295 length-delimited(wire_type=2)的編碼方式:key+length+content, key的編碼方式是統一的,length采用varints編碼方式,content就是由length指定的長度的Bytes。3)ProtoBuf編解碼中字段順序(Field order)的問題:(a) 編碼/解碼與字段順序無關,這一點由key-value機制就能保證(b)對于未知的字段,編碼的時候會把它寫在序列化完的已知字段后面。

總結

以上是生活随笔為你收集整理的protobuf中 repeated[Ptr]Field的序列化的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。