byte型配列との相互変換

データ型の相互変換ではint型やstring型などを相互変換する方法を解説しましたが、プログラミングでは時に様々な値をbyte型の配列で扱う場合があります。
ここではデータ型とbyte型配列(バイナリ)とを相互変換する方法を説明します。

int型→string型などのデータ型の変換はデータ型の相互変換を参照してください。

BitConverterクラス

BitConverterクラスはbyte型配列との相互変換メソッドを提供するクラスです。
メソッドはすべて静的メソッドです。

BitConverter.GetBytes

int型などをbyte型配列に変換するにはBitConverter.GetBytesメソッドを使用します。


byte[] byteInts = BitConverter.GetBytes(12345);
byte[] byteDoubles = BitConverter.GetBytes(1.2345);

//16進数で表示
foreach (var x in byteInts)
    Console.Write("{0:X2}", x);

Console.WriteLine();

foreach (var x in byteDoubles)
    Console.Write("{0:X2}", x);
39300000
8D976E1283C0F33F

BitConverter.GetBytesメソッドは基本的な値型(プリミティブ型)を全てサポートしています。

エンディアン

数値などをbyte配列に変換するとき、どのような順序で並べるかの決まりをエンディアン(バイトオーダー)といいます。


//00 00 00 01
byte[] bytes1 = BitConverter.GetBytes(1);

//00 00 00 0F
byte[] bytes2 = BitConverter.GetBytes(15);

//00 00 00 10
byte[] bytes3 = BitConverter.GetBytes(16);

//00 00 00 1F
byte[] bytes4 = BitConverter.GetBytes(31);

//00 00 00 FF
byte[] bytes5 = BitConverter.GetBytes(255);

//00 00 01 00
byte[] bytes6 = BitConverter.GetBytes(256);

//Console.WriteLineは省略
01 00 00 00
0F 00 00 00
10 00 00 00
1F 00 00 00
FF 00 00 00
00 01 00 00

16通りの値は4bitで表せますから(2の4乗)、4bit+4bit=8bit=1byteとなり、0~Fまでの16通りの値ふたつで1バイトを表します。
int型は4バイトなので、2×4=8個の値で表します。

上のコードの実行結果を見ると、桁の低い方から順に並べられているのが分かります。
このような並べ方をリトルエンディアンといい、Windows環境は基本的にリトルエンディアンとなっています。

int型の「1」を「00 00 00 01」と表現する方法をビッグエンディアンといいます。
その他ミドルエンディアンというものも存在します。

このようなバイトの並びは一つのプログラムで完結するような場合には気にする必要はありません。
例えば他の環境で作成されたファイルを読み込む場合や、他の環境とネットワークを通じて通信する場合に問題となる場合があります。

.NET Frameworkではバイナリとの変換はリトルエンディアンで扱います。
その他のエンディアンで扱うメソッドは標準では提供されていないので、必要ならば自作するか標準以外のライブラリを使用する必要があります。

BitConverter.To○○

byte型配列を元のデータ型に戻すには以下のメソッドを使用します。

BitConverter.ToBoolern bool型
BitConverter.ToChar char型
BitConverter.ToInt16
BitConverter.ToUint16
short型
ushort型
BitConverter.ToInt32
BitConverter.ToUInt32
int型
uint型
BitConverter.ToInt64
BitConverter.ToUInt64
long型
ulong型
BitConverter.ToSingle float型
BitConverter.ToDouble double型

byte[] byteInts = BitConverter.GetBytes(12345);
byte[] byteDoubles = BitConverter.GetBytes(1.2345);

int num = BitConverter.ToInt32(byteInts, 0);
double real = BitConverter.ToDouble(byteDoubles, 0);

Console.WriteLine(num);
Console.WriteLine(real);
12345
1.2345

第二引数はbyte型配列の読み取り開始位置を指定します。
これは複数のデータが含まれるbyte型配列から特定の位置のデータを取得します。


byte[] byteInts = BitConverter.GetBytes(12345);
byte[] byteDoubles = BitConverter.GetBytes(1.2345);

//二つの配列を結合
byte[] bytes = byteInts.Concat(byteDoubles).ToArray();

int num = BitConverter.ToInt32(bytes, 0);
double real = BitConverter.ToDouble(bytes, 4);
12345
1.2345

int型なら4バイト分、double型なら8バイト分の長さが指定位置から取得されます。
指定のデータ型のサイズ以上の長さがないとエラー(例外)になります。

Encodingクラス

文字列をバイト型配列に変換するにはEncodingクラスを使用します。
(System.Text名前空間)

文字列→バイト配列

Encodingクラスにはいくつかの文字コードがあらかじめ用意されているので、これらのGetBytesメソッドで文字列をバイト型配列に変換します。


byte[] ASCII = Encoding.ASCII.GetBytes("あいうえお");
byte[] UTF7  = Encoding.UTF7.GetBytes("あいうえお");
byte[] UTF8  = Encoding.UTF8.GetBytes("あいうえお");
byte[] UTF16 = Encoding.Unicode.GetBytes("あいうえお");
byte[] UTF32 = Encoding.UTF32.GetBytes("あいうえお");

ASCIIは日本語を扱うことはできないので、上記のコード1行目は変換に失敗します。

「Encoding.Unicode」はUTF-16を意味します。

これら以外の文字コードを使用する場合はEncoding.GetEncodingメソッドを使用します。


byte[] SJIS1 = Encoding.GetEncoding("shift-jis").GetBytes("あいうえお");
byte[] SJIS2 = Encoding.GetEncoding(932).GetBytes("あいうえお");

引数には文字コードを表す文字列か数値を指定します。
「932」はShift-JISを表す番号で、上記の例はどちらもShift-JISで変換します。
引数に指定できる文字列や数値は以下を参照してください。
Encoding Class (System.Text) | Microsoft Doc

バイト配列→文字列

バイト配列を文字列に変換するにはEncoding.GetStringメソッドを使用します。


string utf8  = Encoding.UTF8.GetString(UTF8);
string utf16 = Encoding.Unicode.GetString(UTF16);
string sjis  = Encoding.GetEncoding("shift-jis").GetString(SJIS);

バイト配列に変換した時の文字コードと複合時の文字コードが一致しないと文字化けが発生します。

第二引数に変換開始位置、第三引数に変換するバイト数を指定することでバイト配列の特定の位置の変換ができます。


//配列の3番目から6バイト分を変換
//UTF16は2バイトで1文字
string str = Encoding.Unicode.GetString(UTF16, 2, 6);
Console.WriteLine(str);
いうえ