Golang

Goでバイナリを固定長で読んでいくときのメモ

バイナリの先頭nバイトを読みたいときというのがあると思う。先頭4バイトを読むとデータのサイズが入ってて、その後nバイトがデータとか、そういうやつ。固定長で読む良い方法があんまりなくて(あったらおしえてくれ)、自分でsliceを所望のサイズでmakeして、そこにio.Readする。ちょっとはまったのでメモ。

 

  file, _ := os.Open("test.bin")

  // 例1
  buf := make([]byte, 256)
  read_size, _ := file.Read(buf)
  fmt.Println(read_size, "bytes read.", string(buf))

  // 例2
  buf2 := make([]byte, 256)
  read_size2, _ := io.ReadFull(file, buf2)
  fmt.Println(read_size2, "bytes read.", string(buf2))

 

何も考えずにやると上の例1みたいになると思うが、これだとバッファが埋まるまで読んでくれないことがあってはまる(read_sizeが256にならない場合がある)。

そもそも、io.Readは1回呼ばれたときの読み出しサイズが保証されていないので、io.Readで読み出されるサイズはなんかよくわからないけど読み出し元の種類とか状況によるっぽい。数バイトくらいなら問題ないことが多いが、サイズが大きくなってくると1回のio.Readでバッファを埋められないことがでてくる。なので、io.ReadFullを使う(例2)。これならバッファが埋まるまでio.Readを繰り返し呼んでくれる。テキストファイルの読み込みとかだとio.Readを直接使うことはほとんどないが、バイナリを扱うときもできるだけ使わないのがよさそう。

ちなみに[]byteをstringにcastできるらしい。ASCII専用だろうが。

 

あと、2/4/8バイトを読んで数値として解釈するのはもっと簡単で、encoding/binaryをimportして、

  var num uint16
  binary.Read(file, binary.LittleEndian, &num)

とすればnumの型の分(この場合は2バイト)だけ読み出してreaderを進めてくれる。楽。

追記(2016/04/16):

encoding/binary/binary.goを読むと、io.ReadFullを使っていることがわかる。なるほど。

あと、binary.Readは各整数型以外にもそれぞれのスライスに対応しているらしい。

  num := make([]uint16, 3)
  binary.Read(file, binary.LittleEndian, &num)
  fmt.Println(num)
  // => [14648 24880 25442]

低温調理器を自作する – TCP talkers – (Web UI編)

さて、デーモン化したはよいが、結局温度設定を突っ込むにはRedisを介さなければいけないのであった。不便で仕方ないのでWebから設定できるようにしたい。スマホから肉を煮たい。まさに人間の根源的な欲求だと思う。というわけで今回はWebから設定できるようにした。

Cooker-block-diagram

 

図だけでもそれっぽくかわいい感じにつくればそれっぽく見えると思っていたのだが、どうやらそんなこともなさそうである。

Continue reading