1. 程式人生 > 實用技巧 >golang中encoding/binary包

golang中encoding/binary包

1、golang包中的binary包是什麼?
2、binary為我們開發者提供了哪些內容?以及怎麼使用?
3、編解碼有哪幾種方法?

轉化成二進位制格式與原本資料轉字串相比會更節省空間

一、golang包中的binary包是什麼?
此包實現了對資料與byte之間的轉換,以及varint的編解碼。

二、binary為我們開發者提供了哪些內容?以及怎麼使用?
資料的byte序列化轉換

func Read(r io.Reader, order ByteOrder, data interface{}) error
func Write(w io.Writer, order ByteOrder, data 
interface{}) error func Size(v interface{}) int

uvarint和varint的編解碼

func PutUvalint(buf []byte, x uint64) int
func PutVarint(buf []byte, x int64) int
func Uvarint(buf []byte) (uint64, int)
func Varint(buf []byte) (int64, int)
func ReadUvarint(r io.ByteReader) (uint64, error)
func ReadVarint(r io.ByteReader) (int64, error)

結構體

type ByteOrder:可以定義自己的位元組序結構,用於序列化和反序列化資料。

1)func Read(r io.Reader, order ByteOrder, data interface{}) error

引數列表:
1)r  可以讀出位元組流的資料來源
2)order  特殊位元組序,包中提供大端位元組序和小端位元組序
3)data  需要解碼成的資料
返回值:error  返回錯誤
功能說明:Read從r中讀出位元組資料並反序列化成結構資料。data必須是固定長的資料值或固定長資料的slice。從r中讀出的資料可以使用特殊的 位元組序來解碼,並順序寫入value的欄位。當填充結構體時,使用(_)名的欄位講被跳過。

程式碼案例

package main

import (
    "fmt"
    "log"
    "bytes"
    "encoding/binary"
)

func main() {
    var pi float64
    b := []byte{0x18,0x2d,0x44,0x54,0xfb,0x21,0x09,0x40}
    buf := bytes.NewBuffer(b)
    err := binary.Read(buf, binary.LittleEndian, &pi)
    if err != nil {
        log.Fatalln("binary.Read failed:", err)
    }
    fmt.Println(pi)
}

2)Write(w io.Writer, order ByteOrder, data interface{}) error

引數列表:
1)w  可寫入位元組流的資料
2)order  特殊位元組序,包中提供大端位元組序和小端位元組序
3)data  需要解碼的資料
返回值:error  返回錯誤
功能說明:
Write講data序列化成位元組流寫入w中。data必須是固定長度的資料值或固定長資料的slice,或指向此類資料的指標。寫入w的位元組流可用特殊的位元組序來編碼。另外,結構體中的(_)名的欄位講忽略。

程式碼案例:

package main

import (
    "bytes"
    "math"
    "encoding/binary"
    "log"
    "fmt"
)

func main() {
    buf := new(bytes.Buffer)
    pi := math.Pi

    err := binary.Write(buf, binary.LittleEndian, pi)
    if err != nil {
        log.Fatalln(err)
    }
    fmt.Println(buf.Bytes())
}

3)func Size(v interface{}) int

引數列表:v  需要計算長度的資料
返回值:int 資料序列化之後的位元組長度
功能說明:
Size講返回資料系列化之後的位元組長度,資料必須是固定長資料型別、slice和結構體及其指標。

程式碼例項

package main

import (
    "fmt"
    "encoding/binary"
)

func main() {
    var a int
    p := &a
    b := [10]int64{1}
    s := "adsa"
    bs := make([]byte, 10)

    fmt.Println(binary.Size(a)) // -1
    fmt.Println(binary.Size(p)) // -1
    fmt.Println(binary.Size(b)) // 80
    fmt.Println(binary.Size(s)) // -1
    fmt.Println(binary.Size(bs))    // 10
}

4)func PutUvarint(buf []byte, x uint64) int

引數列表:
1)buf  需寫入的緩衝區
2)x  uint64型別數字
返回值:
1)int  寫入位元組數。
2)panic  buf過小。
功能說明:
PutUvarint主要是講uint64型別放入buf中,並返回寫入的位元組數。如果buf過小,PutUvarint將丟擲panic。

程式碼案例

package main

import (
    "encoding/binary"
    "fmt"
    "strconv"
)

func main() {
    u16 := 1234
    u64 := 0x1020304040302010
    sbuf := make([]byte, 4)
    buf := make([]byte, 10)

    ret := binary.PutUvarint(sbuf, uint64(u16))
    fmt.Println(ret, len(strconv.Itoa(u16)), sbuf)

    ret = binary.PutUvarint(buf, uint64(u64))
    fmt.Println(ret, len(strconv.Itoa(u64)), buf)
}
/*
輸出結果:
2 4 [210 9 0 0]
9 19 [144 192 192 129 132 136 140 144 16 0]
會發現轉成二進位制來傳輸資料,比直接轉字串之後轉[]byte這種方式傳更節省傳輸空間
 */

5)func PutVarint(buf []byte, x int64) int

引數列表:
1)buf  需要寫入的緩衝區
2)x int64型別數字
返回值:
1)int  寫入位元組數
2)panic  buf過小
功能說明:
PutVarint主要是講int64型別放入buf中,並返回寫入的位元組數。如果buf過小,PutVarint將丟擲panic。

程式碼案例:

package main

import (
    "encoding/binary"
    "fmt"
    "strconv"
)

func main() {
    i16 := 1234
    i64 := -1234567890
    sbuf := make([]byte, 4)
    buf := make([]byte, 10)

    ret := binary.PutVarint(buf, int64(i16))
    fmt.Println(ret, len(strconv.Itoa(i16)), sbuf)

    ret = binary.PutVarint(buf, int64(i64))
    fmt.Println(ret, len(strconv.Itoa(i64)), buf)
}
/*
2 4 [0 0 0 0]
5 11 [163 139 176 153 9 0 0 0 0 0]
 */

6)func Uvarint(buf []byte) (uint64, int)

引數列表:buf  需要解碼的緩衝區
返回值:
1)uint64  解碼的資料。
2)int  解析的位元組數。
功能說明:
Uvarint是從buf中解碼並返回一個uint64的資料,及解碼的位元組數(>0)。如果出錯,則返回資料0和一個小於等於0的位元組數n,其意義為:
1)n == 0: buf太小
2)n < 0: 資料太大,超出uint64最大範圍,且-n為已解析位元組數

程式碼案例

package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    sbuf := []byte{}
    buf := []byte{144,192,192,132,136,140,144,16,0,1,1}
    bbuf := []byte{144,192,192,129,132,136,140,144,192,192,1,1}

    num, ret := binary.Uvarint(sbuf)
    fmt.Println(num, ret)

    num, ret = binary.Uvarint(buf)
    fmt.Println(num, ret)

    num, ret = binary.Uvarint(bbuf)
    fmt.Println(num, ret)
}
  1. func Varint(buf []byte) (int64, int)
引數列表: buf  需要解碼的緩衝區
返回值:
1) int64 解碼的資料
2) int  解析的位元組數
功能說明:
Varint是從buf中解碼並返回一個int64的資料,及解碼的位元組數(>0).如果出錯,則返回資料0和一個小於等於0的位元組數n,其意義為:
1) n == 0: buf太小
2) n < 0: 資料太大,超出64位,且-n為已解析位元組數

程式碼案例

package main

import (
  "encoding/binary"
    "fmt"
)

func main() {
    var sbuf []byte
    var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
    var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

    num, ret := binary.Varint(sbuf)
    fmt.Println(num, ret) //0 0

    num, ret = binary.Varint(buf)
    fmt.Println(num, ret) //580990878187261960 9

    num, ret = binary.Varint(bbuf)
    fmt.Println(num, ret) //0 -11
}
  1. func ReadUvarint(r io.ByteReader) (uint64, error)
引數列表:
返回值:
1) uint64  解析出的資料
2) error  返回的錯誤
功能說明:
ReadUvarint從r中解析並返回一個uint64型別的資料及出現的錯誤.
功能說明:
ReadUvarint從r中解析並返回一個uint64型別的資料及出現的錯誤.

程式碼案例

package main

import (
  "bytes"
    "encoding/binary"
    "fmt"
)

func main() {
    var sbuf []byte
    var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
    var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

    num, err := binary.ReadUvarint(bytes.NewBuffer(sbuf))
    fmt.Println(num, err) //0 EOF

    num, err = binary.ReadUvarint(bytes.NewBuffer(buf))
    fmt.Println(num, err) //1161981756374523920 <nil>

    num, err = binary.ReadUvarint(bytes.NewBuffer(bbuf))
    fmt.Println(num, err) //4620746270195064848 binary: varint overflows a 64-bit integer
}
  1. func ReadVarint(r io.ByteReader) (int64, error)
引數列表: r  實現ByteReader介面的物件
返回值: 
1) int64  解析出的資料
2) error  返回的錯誤
功能說明:
ReadVarint從r中解析並返回一個int64型別的資料及出現的錯誤.

程式碼案例

package main

import (
  "bytes"
    "encoding/binary"
    "fmt"
)

func main() {
    var sbuf []byte
    var buf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 16, 0, 1, 1}
    var bbuf []byte = []byte{144, 192, 192, 129, 132, 136, 140, 144, 192, 192, 1, 1}

    num, err := binary.ReadVarint(bytes.NewBuffer(sbuf))
    fmt.Println(num, err) //0 EOF

    num, err = binary.ReadVarint(bytes.NewBuffer(buf))
    fmt.Println(num, err) //580990878187261960 <nil>

    num, err = binary.ReadVarint(bytes.NewBuffer(bbuf))
    fmt.Println(num, err) //2310373135097532424 binary: varint overflows a 64-bit integer
}

三、編解碼有哪幾種方法?
編碼

  1. func Write(w io.Writer, order ByteOrder, data interface{}) error
  2. func PutUvarint(buf []byte, x uint64) int
  3. func PutVarint(buf []byte, x int64) int

解析
1)func Uvarint(buf []byte) (uint64, int)
2)func Varint(buf []byte) (int64, int)
3)func ReadUvarint(r io.ByteReader) (uint64, error)
4)func ReadVarint(r io.ByteReader) (int64, error)

5人點贊 GO語言標準庫詳解

作者:laijh
連結:https://www.jianshu.com/p/ec461b39bf43
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。