TLV格式 及 VARINT數值壓縮存儲方法

使用Thrift格式進行數據序列化反序列化,thrift的存儲格式,主要使用thrift的TCompactProtocol。

發現該序列化方式主要使用了TLV格式式來存儲每個字段,使用VARINT來表示其中的L。

1. TLV 格式

很簡單,Type-length-value(類型-長度-值)。在一串字節中,使用該方式標示出一個自定義的字段。

三個域的表示方式均可自定義。如使用1個字節標示數據類型T,使用4個字節標示數據長度L,之後使用L個字節來表示數據的值。(其實Thrift的TBinaryProtocol就是這種方式)

2. VARINT 數值壓縮存儲

c中int使用4個固定字節表式,即使數字很小。假如使用int16,則不能表示較大的數字。

而VARINT是一種可變長度的表示數字的方法,當數字較小時可以使用1個字節,如果比較大需要利用5個。

3.java實現

int轉爲varint,TCompact 的java實現如下:

  private void writeVarint32(int n) {                                                                                  
    int idx = 0;
    while (true) {
      if ((n & ~0x7F) == 0) {
        i32buf[idx++] = (byte)n;
        break;
      } else {
        i32buf[idx++] = (byte)((n & 0x7F) | 0x80);
        n >>>= 7;
      }
    }
    trans_.write(i32buf, 0, idx); // trans_不用管,可以看作字節流
  }  

其實就是,依次從字節串的末尾選取7位,最高位添加1或0構造出1個字節。並且,只有最後一次選取時最高位置爲0,此時剩餘的位構成到數字是小於 1000 0000,的所以添加0並不會影響其大小。如下:

10進制: 296
16進制: x01 x28
2進制: 0000 0001 0010 1000
轉換:a --- ---- ==> 1010 1000 選擇末7位,最高位置爲1

 b    -- ---- -          ==> 1010 1000 0000 0010    右移7位,選擇末7位,最高位置爲0

VARINT: 1010 1000 0000 0010
16進制:xa8 x02
很明顯,通過這種方法,我們得到的VARINT,依次讀取每個字節,只有表示該VARINT的最後一個字節,最高位爲0。所以,當我們讀取VARINT時,只要讀取到最高位爲0的字節時,就表示已經是VARINT的最後一個字節了。

結合TLV就是:先讀取1個字節得到類型T;然後讀取n個字節計算出長度L,其中第n個字節的最高位爲0;然後讀取L個字節,表示我們的V。

4.python實現

最後,我們看下讀取VARINT時,python的處理方法:

def readVarint(trans):
  result = 0 
  shift = 0 
  while True:
    x = trans.readAll(1)    // 讀取下一個字符
    byte = ord(x)              // 轉成整數表示
    result |= (byte & 0x7f) << shift // 將該字節去掉最高位放在已有結果的左側
    if byte >> 7 == 0:       // 如果該字節最高位是0,結束
      return result
    shift += 7
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章