W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
?goframe
?框架提供了獨立的二進制數(shù)據(jù)操作包?gbinary
?,主要用于各種數(shù)據(jù)類型與?[ ]byte
?二進制類型之間的相互轉(zhuǎn)換;以及針對于整型數(shù)據(jù)進行精準按位處理的功能。常用于網(wǎng)絡(luò)通信時數(shù)據(jù)編碼/解碼,以及數(shù)據(jù)文件操作時的編碼/解碼。
使用方式:
import "github.com/gogf/gf/v2/encoding/gbinary"
接口文檔:
https://pkg.go.dev/github.com/gogf/gf/v2/encoding/gbinary
用于二進制數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換處理的接口文檔如下:
func Encode(vs ...interface{}) ([]byte, error)
func EncodeInt(i int) []byte
func EncodeInt8(i int8) []byte
func EncodeInt16(i int16) []byte
func EncodeInt32(i int32) []byte
func EncodeInt64(i int64) []byte
func EncodeUint(i uint) []byte
func EncodeUint8(i uint8) []byte
func EncodeUint16(i uint16) []byte
func EncodeUint32(i uint32) []byte
func EncodeUint64(i uint64) []byte
func EncodeBool(b bool) []byte
func EncodeFloat32(f float32) []byte
func EncodeFloat64(f float64) []byte
func EncodeString(s string) []byte
func Decode(b []byte, vs ...interface{}) error
func DecodeToInt(b []byte) int
func DecodeToInt8(b []byte) int8
func DecodeToInt16(b []byte) int16
func DecodeToInt32(b []byte) int32
func DecodeToInt64(b []byte) int64
func DecodeToUint(b []byte) uint
func DecodeToUint8(b []byte) uint8
func DecodeToUint16(b []byte) uint16
func DecodeToUint32(b []byte) uint32
func DecodeToUint64(b []byte) uint64
func DecodeToBool(b []byte) bool
func DecodeToFloat32(b []byte) float32
func DecodeToFloat64(b []byte) float64
func DecodeToString(b []byte) string
支持按位處理的接口文檔如下:
func EncodeBits(bits []Bit, i int, l int) []Bit
func EncodeBitsWithUint(bits []Bit, ui uint, l int) []Bit
func EncodeBitsToBytes(bits []Bit) []byte
func DecodeBits(bits []Bit) uint
func DecodeBitsToUint(bits []Bit) uint
func DecodeBytesToBits(bs []byte) []Bit
其中的?Bit
?類型表示一個二進制數(shù)字(0或1),其定義如下:
type Bit int8
我們來看一個比較完整的二進制操作示例,基本演示了絕大部分的二進制轉(zhuǎn)換操作。
github.com/gogf/gf/v2/blob/master/.example/encoding/gbinary/binary.go
package main
import (
"fmt"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/encoding/gbinary"
)
func main() {
// 使用gbinary.Encoded對基本數(shù)據(jù)類型進行二進制打包
if buffer := gbinary.Encode(18, 300, 1.01); buffer != nil {
// glog.Error(err)
} else {
fmt.Println(buffer)
}
// 使用gbinary.Decode對整形二進制解包,注意第二個及其后參數(shù)為字長確定的整形變量的指針地址,字長確定的類型,
// 例如:int8/16/32/64、uint8/16/32/64、float32/64
// 這里的1.01默認為float64類型(64位系統(tǒng)下)
if buffer := gbinary.Encode(18, 300, 1.01); buffer != 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!")))
}
以上程序執(zhí)行結(jié)果為:
[18 44 1 41 92 143 194 245 40 240 63]
18 300 1.01
1
300
70000
2000000000
500000000000
1
300
70000
2000000000
500000000000
100
100
100
100
100
100
100
100
I'm string!
?gbinary.Encode
?方法是一個非常強大靈活的方法,可以將所有的基本類型轉(zhuǎn)換為二進制類型(?[ ]byte
?)。在?gbinary.Encode
?方法內(nèi)部,會自動對變量進行長度計算,采用最小二進制長度來存放該變量的二進制值。例如,針對int類型值為1的變量,?gbinary.Encode
?將只會用1個byte來存儲,而int類型值為300的變量,將會使用2個byte來存儲,盡量減少二進制結(jié)果的存儲空間。因此,在解析的時候要非常注意?[ ]byte
?的長度,建議能夠確定變量長度的地方,在進行二進制編碼/解碼時,盡量采用形如int8/16/32/64的定長基本類型來存儲變量,這樣解析的時候也能夠采用對應(yīng)的變量形式進行解析,不易產(chǎn)生錯誤。
?gbinary
?包也提供了一系列?gbinary.Encode*
?的方法,用于將基本數(shù)據(jù)類型轉(zhuǎn)換為二進制。其中,?gbinary.EncodeInt/gbinary.EncodeUint
?也是會在內(nèi)部自動識別變量值大小,返回不定長度的?[ ]byte
?值,長度范圍1/2/4/8。
在二進制類型的解析操作中,二進制的長度(?[ ]byte
?的長度)是非常重要的,只有給定正確的長度才能執(zhí)行正確的解析,因此?gbinary.Decode
?方法給定的變量長度必須為確定長度類型的變量,例如:int8/16/32/64、uint8/16/32/64、float32/64,而如果給定的第二個變量地址對應(yīng)的變量類型為int/uint,無法確定長度,因此解析會失敗。
此外,?gbinary
?包也提供了一系列?gbinary.DecodeTo*
?的方法,用于將二進制轉(zhuǎn)換為特定的數(shù)據(jù)類型。其中,?gbinary.DecodeToInt/gbinary.DecodeToUint
?方法會對二進制長度進行自動識別解析,支持的二進制參數(shù)長度范圍1-8。
?gbinary
?的Bits相關(guān)操作簡化了底層二進制位操作的復(fù)雜度,為精準的數(shù)據(jù)按位處理提供了可能。
例如,針對于物聯(lián)網(wǎng)項目而言,傳感器設(shè)備是比較常見的硬件設(shè)備,我們以下的示例展示了網(wǎng)關(guān)向平臺上報其下管理的傳感器的狀態(tài)信息。由于傳感器狀態(tài)只有4種(0:已下線,1:開啟, 2:關(guān)閉, 3:待機),正好對應(yīng)了2個二進制位(2 bit),因此1byte(8 bit)便可以表示出4個傳感器設(shè)備的狀態(tài)。
看以下的例子,用以上報平臺100個傳感器已開啟,上報的狀態(tài)順序便是傳感器在網(wǎng)關(guān)下端口順序(索引從0開始):
https://github.com/gogf/gf/v2/blob/master/.example/encoding/gbinary/bits1.go
package main
import (
"fmt"
"github.com/gogf/gf/v2/encoding/gbinary"
)
func main() {
// 傳感器狀態(tài),0:已下線, 1:開啟, 2:關(guān)閉, 3:待機
count := 100
status := 1
// 網(wǎng)關(guān)編碼
bits := make([]gbinary.Bit, 0)
for i := 0; i < count; i++ {
bits = gbinary.EncodeBits(bits, int(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)
}
執(zhí)行后輸出結(jié)果為:
buffer length: 25
alived sensor: 100
可以看到,上報100個傳感器的狀態(tài)數(shù)據(jù)只需要25byte即可,該示例中我們在平臺上解碼后統(tǒng)計開啟的傳感器數(shù)量有100臺。
我們再看看一個實戰(zhàn)的例子。?gkvdb
?是?gf
?框架相同作者開發(fā)的基于?DRH
?算法的高性能?Key-Value
?嵌入式數(shù)據(jù)庫,其中元數(shù)據(jù)的存儲數(shù)據(jù)結(jié)構(gòu)如下:
[鍵名哈希64(64bit,8byte) 鍵名長度(8bit,1byte) 鍵值長度(24bit,3byte) 數(shù)據(jù)文件偏移量(40bit,5byte)](變長)
我們使用一條元數(shù)據(jù)來演示編碼/解碼操作。
github.com/gogf/gf/v2/blob/master/.example/encoding/gbinary/bits2.go
package main
import (
"fmt"
"github.com/gogf/gf/v2/encoding/gbinary"
)
func main() {
// Meta元數(shù)據(jù)文件數(shù)據(jù)結(jié)構(gòu):[鍵名哈希64(64bit,8byte) 鍵名長度(8bit,1byte) 鍵值長度(24bit,3byte) 數(shù)據(jù)文件偏移量(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))
/* 文件存儲及數(shù)據(jù)查詢過程忽略,這里只展示元數(shù)據(jù)編碼/解碼示例 */
// 解碼
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]))
}
運行后,輸出結(jié)果為:
meta length: 17
hash : 521369841259754125
klen : 12
vlen : 35535
offset: 80000000
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: