LoginSignup
96
69

More than 5 years have passed since last update.

Go でバイナリ処理

Posted at

Go でバイナリをゴリゴリ処理するときに覚えておくと良さそうなもの。

進数表示

fmt.Printf("%b", 10) // 1010
fmt.Printf("%d", 10) // 10
fmt.Printf("%x", 10) // a
fmt.Printf("%X", 10) // A

byte

byte 自体は uint8 のエイリアス
オクテットストリームは []byte が基本

b := []byte{0x01, 0x02, 0x03}

単なるスライスなので、 Array を直で触るのでなければ、
これが一番低レベルな表現と言える。

bytes

bytes は []byte を操作するための便利メソッドを提供する。

bytes.Equal([]byte{1,2,3}, []byte{4,5}) // false

ちなみに、バイトを文字とみなせば string なので、
bytes の関数は strings とインタフェースが似ている。

bytes.Buffer

bytes に含まれるが、 []byte をラップして Read(), Write() などを付けるもの。
つまり Buffer にすれば io.ReadWriter を満たすので、
io.ReadWriter を引数にするライブラリなどで使える。(ioutil / bufio etc)

func main() {
    buf := bytes.NewBuffer([]byte{1, 2, 3})

    buf.Write([]byte{4, 5, 6})

    b := make([]byte, 3)
    buf.Read(b)                 // 1, 2, 3

    log.Println(b, buf.Bytes()) // 4, 5, 6
}

一旦読んでから、読んだ分を戻すことができる UnreadByte() と
中の []byte が取り出せる Bytes() を覚えとくと良い。

bytes.Reader

Buffer と違い readonly
io.Reader と io.Seeker etc があり、 Read(), Seek() ができる。

encoding/binary

[]byte と固定長型の変数(unit64 とか) 間でエンコード/デコードできる。
エンディアンも指定できる。

ネットワークプロトコルのパーサとか書く場合は必須。
例えば、 4byte づつ key, val を表すプロトコルがあった場合。

type Row struct {
    Key uint16
    Val uint16
}

func (r Row) String() string {
    return fmt.Sprintf("(%s: %v)", string(r.Key), r.Val)
}

func main() {
    buf := bytes.NewBuffer([]byte{0x0, 97, 0x3, 0x1})
    row := Row{}
    binary.Read(buf, binary.BigEndian, &row.Key)
    binary.Read(buf, binary.BigEndian, &row.Val)

    log.Println(row)
}

96
69
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
96
69