Crystal のバイナリデータ読み込みは C みたいでつらい

これは「Ruby脳にはCrystalつらい Advent Calendar 2015」の21日目の記事です。

qiita.com

Crystal の String は UTF-8 固定なのでバイナリデータを String で扱うことはできません。

バイナリデータを扱うには String ではなく Slice を使います。

Slice(UInt8).new(1024) とすると 1024バイトのメモリが獲得されます。C の calloc(sizeof(char), 1024) みたいな感じですね。

Slice のインスタンスは配列と同じような感じで使えますが、長さは固定で拡張したり縮小したりはできません。

slice = Slice(UInt8).new(5)
slice[0] = 11u8
slice[1] = 22u8
slice[2] = 33u8
slice   #=> [11, 22, 33, 0, 0]

File や Socket 等の IO からバイナリデータを読み込むには IO#read を使います。

File.open("/etc/hosts") do |f|
  buf = Slice(UInt8).new(1024)
  length = f.read(buf)
  buf[0, length]
end

読み込むためのバッファを用意して、IO#read の戻り値で読み込んだバイト数を調べて…というような感じでやるしかないようです。 まるで C みたいで、ちょっとつらい。