binary
它的作用用一句話說就是:實(shí)現(xiàn)數(shù)據(jù)與二進(jìn)制之間的雙向轉(zhuǎn)換
它有許多使用場(chǎng)景,比如:
- 讀任ǖ(解析)網(wǎng)絡(luò)過來的二進(jìn)制數(shù)據(jù)
- 讀取一個(gè)二進(jìn)制文件
- 將一個(gè)數(shù)據(jù)寫成二進(jìn)制
大小端字節(jié)序
開始之前先大概說下翅溺,大小端字節(jié)序,簡(jiǎn)單理解就是字節(jié)的編碼順序,一個(gè)從高位開始糜俗,一個(gè)從低位開始校翔。
我們使用時(shí)候主要需要保證讀和寫的順序保持一致就行,如果需要詳細(xì)了解可以看這篇
1. 單一數(shù)據(jù)轉(zhuǎn)換
好啦弟跑!我們開始來看最簡(jiǎn)單的,將一個(gè)簡(jiǎn)單數(shù)據(jù),比如一個(gè)字符防症、一個(gè)數(shù)值轉(zhuǎn)換成二進(jìn)制
對(duì)于一些單一的字符讀寫可以使用,binary提供的binary.BigEndian
和 binary.LittleEndian
完成孟辑。
package main
import (
"encoding/binary"
"fmt"
)
func main() {
var a uint64 = 56
// 用于存二進(jìn)制數(shù)據(jù)
bData := make([]byte, 8) // 64位 8個(gè)字節(jié)
// a 寫入到bData中
binary.LittleEndian.PutUint64(bData, a)
// 從bData讀取 數(shù)據(jù)到b中
b := binary.LittleEndian.Uint64(bData)
fmt.Println(b)
}
// 56
2. 復(fù)雜(結(jié)構(gòu)體)數(shù)據(jù)轉(zhuǎn)換
需要注意的是,binary包處理的數(shù)據(jù)必須要有固定的長度,所以對(duì)結(jié)構(gòu)體的字段類型有要求。
package main
import (
"bytes"
"encoding/binary"
"fmt"
)
// 需要注意的是在binary 出來的數(shù)據(jù)必須要有固定的長度
type Data struct {
ID uint16
Temprature float32
Records [4]byte // 4個(gè)長度字節(jié)數(shù)組
}
func main() {
// 準(zhǔn)備好要轉(zhuǎn)換的數(shù)據(jù)
datas := []Data{
{ID: 12, Temprature: 21.8, Records: [4]byte{'A', 'B', 'C', 'D'}},
{ID: 2, Temprature: 28.8, Records: [4]byte{'B', 'B', 'C', 'A'}},
}
// 具有io.Writer 和 io.Reader的 緩沖對(duì)象用于存二進(jìn)制數(shù)據(jù)
var buf = new(bytes.Buffer)
// 將數(shù)據(jù)寫入buf中 記住這里最后一個(gè)參數(shù)必須是引用(比如指針蔫敲,這里切片本身就是引用所以無所謂)
binary.Write(buf, binary.LittleEndian, datas)
parseData := make([]Data, 2) // 存解析出來的數(shù)據(jù)
// 從buf中讀取 解析成Data結(jié)構(gòu)體切片
binary.Read(buf, binary.LittleEndian, parseData)
fmt.Printf("%#v\n", parseData[0])
fmt.Printf("%#v\n", parseData[1])
fmt.Printf("ID: %d , Temprature: %v, Record1: %c\n", parseData[0].ID, parseData[0].Temprature, parseData[0].Records[0])
}
// main.Data{ID:0xc, Temprature:21.8, Records:[4]uint8{0x41, 0x42, 0x43, 0x44}}
// main.Data{ID:0x2, Temprature:28.8, Records:[4]uint8{0x42, 0x42, 0x43, 0x41}}
// ID: 12 , Temprature: 21.8, Record1: A
3. 寫二進(jìn)制數(shù)據(jù)到文件
package main
import (
"bufio"
"encoding/binary"
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("data.bin", os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
fmt.Println("創(chuàng)建文件錯(cuò)誤")
return
}
defer file.Close()
// 封裝一層緩沖區(qū)
buf := bufio.NewWriter(file)
// 寫入緩沖中
binary.Write(buf, binary.LittleEndian, []byte("hello world\n")) // 第一次寫入 12個(gè)字節(jié)
binary.Write(buf, binary.LittleEndian, []byte("beautiful!\n")) // 第二次寫入11字節(jié)
// 從緩沖寫入文件
buf.Flush()
// 從 文件中讀取
f, err := os.Open("data.bin")
if err != nil {
fmt.Println("打開文件失斔撬浴:", err.Error())
return
}
// 構(gòu)造一個(gè)讀bufio
reader := bufio.NewReader(f)
// 第一次讀取 12個(gè)字節(jié)
a := make([]byte, 12)
binary.Read(reader, binary.LittleEndian, a)
fmt.Printf("%s", a)
// 第二次讀取11個(gè)字節(jié)
binary.Read(reader, binary.LittleEndian, a[0:11])
fmt.Printf("%s", a[0:11])
}
// hello world
// beautiful!
4. 總結(jié)
本質(zhì)上binary包只有兩個(gè)操作: 一個(gè)寫,一個(gè)讀;分別對(duì)應(yīng)兩種轉(zhuǎn)換:
- 寫 - (數(shù)據(jù)->二進(jìn)制)
- 讀 - (二進(jìn)制 -> 數(shù)據(jù))