Rubyでバイト列を得る

前提
バイト列の並び(生データ)はStringクラス
Rubyでは、バイト列の並びもStringで表す。
バイト列を表す文字列
文字列ではない単なるバイト列も String オブジェクトで表されます。その時のエンコーディングはASCII-8BIT です。
バイト列の確認方法
実際に、バイト列がどんな様子になっているかを確認したいときは、String.bytes
を使うとよい。
"hello".bytes #=> [104, 101, 108, 108, 111]
Kernel#puts
で確認する場合には、引数に直接生データのStringを渡さないように、注意が必要(後述)。
一言でいうと、出力の際に生データ(バイト列)を文字の並びにエンコードしてしまい、その結果を見ることになるため。
一番混乱が少ないのは、ファイルに吐き出して、そのファイルの中身をhexdump -C <ファイル>
などで見ることだが...

方法
\xXX
をつかう
Stringリテラルるりまのリテラルのところにない?
Array<Integer>#packを使う
Integer97
と37
の並びを、バイト列String\x61\x21
にする:
bytes_str = [97, 37].pack("CC") # "C2", "C*"でもよい
puts bytes_str
#=> a%
puts bytes_str == "\x61\x21"
#=> true
Integer#to_s(16)は違うよ
Kernel.puts
の標準出力などで動作確認をしていると勘違いしやすいけれど...
Integer#to_s(16)
で得られるのは、「そのIntegerを16進表示した場合の 数字の文字 の並び」であって、実際のバイト列ではない。
具体的には、以下の例を見たほうがわかりやすいと思う:
puts 0.to_s(16) #=> "0"(『ゼロ』の一文字)
puts 0.to_s(16).bytes #=> 48
つまり、0.to_s(16)
は、 バイト列的には0x30(10進数で48) になっている。(0x00ではない!)
ASCIIコード表を見ると、確かに「0」の 文字 はバイト列0x30に対応していることがわかる。

Kernel#puts使用時の注意:直接バイト列Stringを引数に渡すと、内容確認はできないよ
バイト列Stringに対してKernel#puts
を使っても、各バイトを対応する文字に直した状態の出力を見せられるだけ。
bytes_str_1 = [97, 37].pack("CC")
puts bytes_str_1
#=> a%
bytes_str_2 = [0, 18].pack("CC")
puts bytes_str_2
#=> □□(対応する文字がないのでTofuになる)
色々試しているとこんがらがるかもしれないが、「Stringの 『生データ』自体は常にバイト列 で、puts
などで標準出力する際に、対応する文字にエンコードしている」ということを考えれば、当然である。
つまり、「Kernel#puts
によって何を見せられているのか」を把握しておくことが大事。
ファイルの中身に吐いたデータをテキストエディタで見ると、文字になっているのも、ファイル中の生データをエディタの画面上に出力する際に、対応する文字にエンコードしているだけ。

これをどっかにおく
[97, 99].pack("CC") == "ac"
#=> true
"\x61\x63" == "ac"
#=> true
"\x00" == [0].pack("C")
#=> true