Ruby バイナリデータの処理関係
画面表示
a = 15 printf("%d => 0x%02x\n", a, a) #=> "15 => 0x0f"
ファイル出力
ファイルにバイナリデータとして書き込みたい場合、Array.packを使用する方法があります。
- Array.pack('c*'): char (8bit 符号付き整数)
- Array.pack('C*'): unsigned char (8bit 符号なし整数)
- Array.pack('s*'): short (16bit 符号付き整数, エンディアン依存)
- Array.pack('S*'): unsigned short (16bit 符号なし整数, エンディアン依存)
- Array.pack('l*'): long (32bit 符号付き整数, エンディアン依存)
- Array.pack('L*'): unsigned long (32bit 符号なし整数, エンディアン依存)
- Array.pack('q*'): long long (64bit 符号付き整数, エンディアン依存)
- Array.pack('Q*'): unsigned long long (64bit 符号なし整数, エンディアン依存)
- Array.pack('m'): base64された文字列。60オクテッドごとと最後に改行コードが付加
-
バイト単位の出力
ファイルにバイト単位でバイナリデータを書き込みたい場合, 以下のようにします。 基本的にはArray.packに、大文字の"C"(8bit 符号無し整数)を指定して使用します。
# 205 = 0xCD, 216 = 0xD8, 255 = 0xFF
data = [205, 216, 0, 255] # 10進数の配列
f = open('tmp.bin', 'wb')
f.write(data.pack('C*')) # 出力は16進数で CD D8 00 FF
f.close
これは以下のようにもできます。
# 205 = 0xCD, 216 = 0xD8, 255 = 0xFF
data = [205, 216, 0, 255] # 10進数の配列
f = open('tmp.bin', 'wb')
data.each do |d|
f.write([d].pack('C')) # 出力は16進数で CD D8 00 FF
end
f.close
間違った例
# 205 = 0xCD, 216 = 0xD8, 255 = 0xFF data = [205, 216, 0, 255] f = open('tmp.bin', 'wb') f.write(data.pack('C')) # 出力は16進数で CD f.closeこれを実行すると、ファイルtmp.bin の中身は、0xCDのみになります。 Array.pack('C') は配列の1つ目のみを処理するので、205以外が無視されます。 data.pack('L')の場合(32ビット符号なしへの変換)、ファイルのバイナリデータは 0xCD, 0, 0, 0 のファイルになります。
base64
base64された文字列を出力したい場合は、Array.packで、"m"を指定します。
data = ["1234ABCD"] f = open('tmp_base64.bin', 'wb') f.write(data.pack('m')) # 出力ファイルの中身 "MTIzNEFCQ0Q=" f.close
間違った例1
data = ["1", "2", "3", "4", "A", "B", "C", "D" ] f = open('tmp_base64_miss.txt', 'wb') f.write(data.pack('m')) # 出力ファイルの中身 "MQ==" f.closeこの出力は、data = ["1"] をbase64 で変換した結果の "MQ==" と同じで、 配列の1つ目だけを変換したものになります。
間違った例2
data = [205, 216, 0, 255] f = open('tmp_base64_miss2.txt', 'wb') f.write(data.pack('m')) f.closeこれを実行すると、以下のようなエラーになります。
binary.rb:29:in `pack': can't convert Fixnum into String (TypeError) from binary.rb:29