gf架構之gbinary - 位元據操作模組

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

文章來源:http://gf.johng.cn/500342

gf架構提供了獨立的位元據操作包gbinary,主要用於各種資料類型與[ ]byte二進位類型之間的相互轉換;以及針對於整型資料進行精準按位處理的功能。常用於網路通訊時資料編碼/解碼,以及資料檔案操作時的編碼/解碼。

用於位元據結構轉換處理的方法列表如下:

func Encode(vs ...interface{}) ([]byte, error)func EncodeInt(i int) []bytefunc EncodeInt8(i int8) []bytefunc EncodeInt16(i int16) []bytefunc EncodeInt32(i int32) []bytefunc EncodeInt64(i int64) []bytefunc EncodeUint(i uint) []bytefunc EncodeUint8(i uint8) []bytefunc EncodeUint16(i uint16) []bytefunc EncodeUint32(i uint32) []bytefunc EncodeUint64(i uint64) []bytefunc EncodeBool(b bool) []bytefunc EncodeFloat32(f float32) []bytefunc EncodeFloat64(f float64) []bytefunc EncodeString(s string) []bytefunc Decode(b []byte, vs ...interface{}) errorfunc DecodeToInt(b []byte) intfunc DecodeToInt8(b []byte) int8func DecodeToInt16(b []byte) int16func DecodeToInt32(b []byte) int32func DecodeToInt64(b []byte) int64func DecodeToUint(b []byte) uintfunc DecodeToUint8(b []byte) uint8func DecodeToUint16(b []byte) uint16func DecodeToUint32(b []byte) uint32func DecodeToUint64(b []byte) uint64func DecodeToBool(b []byte) boolfunc DecodeToFloat32(b []byte) float32func DecodeToFloat64(b []byte) float64func DecodeToString(b []byte) string

支援按位處理的方法列表如下:

func EncodeBits(bits []Bit, i int, l int) []Bitfunc EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bitfunc EncodeBitsToBytes(bits []Bit) []bytefunc DecodeBits(bits []Bit) uintfunc DecodeBitsToUint(bits []Bit) uintfunc DecodeBytesToBits(bs []byte) []Bit

其中的Bit類型表示一個位元字(0或1),其定義如下:

type Bit int8

二進位操作樣本

我們來看一個比較完整的二進位操作樣本,基本示範了絕大部分的二進位轉換操作。

gitee.com/johng/gf/blob/master/geg/encoding/gbinary/binary.go

package mainimport (    "fmt"    "gitee.com/johng/gf/g/os/glog"    "gitee.com/johng/gf/g/encoding/gbinary")func main() {    // 使用gbinary.Encoded對基礎資料型別 (Elementary Data Type)進行二進位打包    if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {        glog.Error(err)    } else {        fmt.Println(buffer)    }    // 使用gbinary.Decode對整形二進位解包,注意第二個及其後參數為字長確定的整形變數的指標地址,字長確定的類型,    // 例如:int8/16/32/64、uint8/16/32/64、float32/64    // 這裡的1.01預設為float64類型(64位系統下)    if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {        glog.Error(err)    } else {        var i1 int8        var i2 int16        var f3 float64        if err := gbinary.Decode(buffer, &i1, &i2, &f3); err != nil {            glog.Error(err)        } else {            fmt.Println(i1, i2, f3)        }    }    // 編碼/解析 int,自動識別變數長度    fmt.Println(gbinary.DecodeToInt(gbinary.EncodeInt(1)))    fmt.Println(gbinary.DecodeToInt(gbinary.EncodeInt(300)))    fmt.Println(gbinary.DecodeToInt(gbinary.EncodeInt(70000)))    fmt.Println(gbinary.DecodeToInt(gbinary.EncodeInt(2000000000)))    fmt.Println(gbinary.DecodeToInt(gbinary.EncodeInt(500000000000)))    // 編碼/解析 uint,自動識別變數長度    fmt.Println(gbinary.DecodeToUint(gbinary.EncodeUint(1)))    fmt.Println(gbinary.DecodeToUint(gbinary.EncodeUint(300)))    fmt.Println(gbinary.DecodeToUint(gbinary.EncodeUint(70000)))    fmt.Println(gbinary.DecodeToUint(gbinary.EncodeUint(2000000000)))    fmt.Println(gbinary.DecodeToUint(gbinary.EncodeUint(500000000000)))    // 編碼/解析 int8/16/32/64    fmt.Println(gbinary.DecodeToInt8(gbinary.EncodeInt8(int8(100))))    fmt.Println(gbinary.DecodeToInt16(gbinary.EncodeInt16(int16(100))))    fmt.Println(gbinary.DecodeToInt32(gbinary.EncodeInt32(int32(100))))    fmt.Println(gbinary.DecodeToInt64(gbinary.EncodeInt64(int64(100))))    // 編碼/解析 uint8/16/32/64    fmt.Println(gbinary.DecodeToUint8(gbinary.EncodeUint8(uint8(100))))    fmt.Println(gbinary.DecodeToUint16(gbinary.EncodeUint16(uint16(100))))    fmt.Println(gbinary.DecodeToUint32(gbinary.EncodeUint32(uint32(100))))    fmt.Println(gbinary.DecodeToUint64(gbinary.EncodeUint64(uint64(100))))    // 編碼/解析 string    fmt.Println(gbinary.DecodeToString(gbinary.EncodeString("I'm string!")))}

以上程式執行結果為:

[18 44 1 41 92 143 194 245 40 240 63]18 300 1.0113007000020000000005000000000001300700002000000000500000000000100100100100100100100100I'm string!
  1. 編碼
    gbinary.Encode方法是一個非常強大靈活的方法,可以將所有的基本類型轉換為二進位類型([ ]byte)。在gbinary.Encode方法內部,會自動對變數進行長度計算,採用最小二進位長度來存放該變數的二進位值。例如,針對int類型值為1的變數,gbinary.Encode將只會用1個byte來儲存,而int類型值為300的變數,將會使用2個byte來儲存,盡量減少二進位結果的儲存空間。因此,在解析的時候要非常注意[ ]byte的長度,建議能夠確定變數長度的地方,在進行二進位編碼/解碼時,盡量採用形如int8/16/32/64的定長基本類型來儲存變數,這樣解析的時候也能夠採用對應的變數形式進行解析,不易產生錯誤。
    gbinary包也提供了一系列gbinary.Encode*的方法,用於將基礎資料型別 (Elementary Data Type)轉換為二進位。其中,gbinary.EncodeInt/gbinary.EncodeUint也是會在內部自動識別變數值大小,返回不定長度的[ ]byte值,長度範圍1/2/4/8。
  2. 解碼
    在二進位類型的解析操作中,二進位的長度([ ]byte的長度)是非常重要的,只有給定正確的長度才能執行正確的解析,因此gbinary.Decode方法給定的變數長度必須為確定長度類型的變數,例如:int8/16/32/64、uint8/16/32/64、float32/64,而如果給定的第二個變數地址對應的變數類型為int/uint,無法確定長度,因此解析會失敗。
    此外,gbinary包也提供了一系列gbinary.DecodeTo*的方法,用於將二進位轉換為特定的資料類型。其中,gbinary.DecodeToInt/gbinary.DecodeToUint方法會對二進位長度進行自動識別解析,支援的二進位參數長度範圍1-8。

按位操作處理樣本

gbinary的Bits相關操作簡化了底層二進位位操作的複雜度,為精準的資料按位處理提供了可能。

  1. 批量感應器狀態資料上報樣本
    例如,針對於物聯網項目而言,感應器裝置是比較常見的硬體裝置,我們以下的樣本展示了網關向平台上報其下管理的感應器的狀態資訊。由於感應器狀態只有4種(0:已下線,1:開啟, 2:關閉, 3:待機),正好對應了2個二進位位(2 bit),因此1byte(8 bit)便可以表示出4個感應器裝置的狀態。看以下的例子,用以上報平台100個感應器已開啟,上報的狀態順序便是感應器在網關下連接埠順序(索引從0開始):

    gitee.com/johng/gf/blob/master/geg/encoding/gbinary/bits1.go

    package mainimport (    "fmt"    "gitee.com/johng/gf/g/encoding/gbinary")func main() {    // 感應器狀態,0:已下線, 1:開啟, 2:關閉, 3:待機    count  := 100    status := 1    // 網關編碼    bits := make([]gbinary.Bit, 0)    for i := 0; i < count; i++ {        bits = gbinary.EncodeBits(bits, uint(status), 2)    }    buffer := gbinary.EncodeBitsToBytes(bits)    fmt.Println("buffer length:", len(buffer))    /* 上報過程忽略,這裡只展示編碼/解碼樣本 */    // 平台解碼    alivecount := 0    sensorbits := gbinary.DecodeBytesToBits(buffer)    for i := 0; i < len(sensorbits); i += 2 {        if gbinary.DecodeBits(sensorbits[i:i+2]) == 1 {            alivecount++        }    }    fmt.Println("alived sensor:", alivecount)}

    執行後輸出結果為:

    buffer length: 25alived sensor: 100

    可以看到,上報100個感應器的狀態資料只需要25byte即可,該樣本中我們在平台上解碼後統計開啟的感應器數量有100台。

  2. gkvdb資料庫META資料結構操作樣本
    我們再看看一個實戰的例子。gkvdb是gf架構相同作者開發的基於DRH演算法的高效能Key-Value嵌入式資料庫,其中中繼資料的儲存資料結構如下:

    [鍵名雜湊64(64bit,8byte) 鍵名長度(8bit,1byte) 索引值長度(24bit,3byte) 資料檔案位移量(40bit,5byte)](變長)

    我們使用一條中繼資料來示範編碼/解碼操作。

    gitee.com/johng/gf/blob/master/geg/encoding/gbinary/bits2.go

    package mainimport (    "fmt"    "gitee.com/johng/gf/g/encoding/gbinary")func main() {    // Meta中繼資料檔案資料結構:[鍵名雜湊64(64bit,8byte) 鍵名長度(8bit,1byte) 索引值長度(24bit,3byte) 資料檔案位移量(40bit,5byte)](變長)    hash   := 521369841259754125    klen   := 12    vlen   := 35535    offset := 80000000    // 編碼    bits   := make([]gbinary.Bit, 0)    bits    = gbinary.EncodeBits(bits, hash,   64)    bits    = gbinary.EncodeBits(bits, klen,    8)    bits    = gbinary.EncodeBits(bits, vlen,   24)    bits    = gbinary.EncodeBits(bits, offset, 40)    buffer := gbinary.EncodeBitsToBytes(bits)    fmt.Println("meta length:", len(buffer))    /* 檔案儲存體及資料查詢過程忽略,這裡只展示中繼資料編碼/解碼樣本 */    // 解碼    metabits := gbinary.DecodeBytesToBits(buffer)    fmt.Println("hash  :", gbinary.DecodeBits(metabits[0  : 64]))    fmt.Println("klen  :", gbinary.DecodeBits(metabits[64 : 72]))    fmt.Println("vlen  :", gbinary.DecodeBits(metabits[72 : 96]))    fmt.Println("offset:", gbinary.DecodeBits(metabits[96 : 136]))}

    運行後,輸出結果為:

    meta length: 17hash  : 521369841259754125klen  : 12vlen  : 35535offset: 80000000

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.