[C#] バイナリファイルの読み込み方まとめ
byte型配列にバイナリファイルの内容を読み込む
System.IO.FileStreamクラスインスタンスのReadメソッドを使うとbyte型配列にファイルの内容を読み込むことが出来ます。
FileStreamクラスのインスタンスを作成するにはSystem.IO.File.OpenReadメソッドを使います。このメソッドは引数で指定されたファイルを読み取り専用で開いたあとFileStreamクラスのインスタンスを返します。その後で作成したインスタンスのReadメソッドでファイルの内容をbyte型配列に代入します。
Readメソッドの第1引数には、内容をセットするbyte型配列
第2引数には読込開始位置(0が先頭)、
第3引数には読込終了位置(末尾までのサイズはLengthプロパティで取得できる)
を指定します。
using System;
using System.IO;
using System.Linq;
class Program
{
public static void Main()
{
// 読み込むファイルのパス
string filePath = @"D:\test.exe";
// FileStreamのインスタンスを作成(usingについては記事後述)
using var fs = File.OpenRead(filePath);
// ファイルの内容を入れるbyte配列を用意
byte[] bytes = new byte[fs.Length];
// バイナリファイルの読込 先頭(0)から末尾(fs.Length)まで
fs.Read(bytes, 0, (int)fs.Length);
// ファイルサイズの表示(先頭から末尾まで読込したのでファイルサイズと同じになる)
Console.WriteLine($"byte型配列の要素数={bytes.Length}");
// 先頭4バイトを表示(byteは0~255の数値)
Console.WriteLine(string.Join(" ", bytes[0..4]));
// 先頭4バイトを16進数で表示
Console.WriteLine(string.Join(" ", bytes[0..4].Select(b => b.ToString("X2"))));
}
}
出力結果はこんな感じです。
byte型配列の要素数=171520
77 90 144 0
4D 5A 90 00
using構文について
本来であればC#でファイルを扱う場合には、ファイルをOpenした後にCloseしないとプログラム実行中はずっとファイルを開いたままの状態になってしまい、他のプログラムから読み書きができなくなってしまうのですが、usingキーワードを変数宣言の前に付けると、その変数が宣言されたブロック内{ } を抜けたあとに自動で後始末(この場合はClose)をしてくれるようになります。
usingキーワードはIDisposableインターフェースを実装しているクラスに対して使うことができます。Closeメソッドを持っているクラスはたいていこのインターフェースを実装しているはずです。
上記のサンプル11行目「using var fs = …」のような書き方はC#8.0から書けるようになりました。それ以前の書き方の場合は、using (変数) { } のような書き方でusingブロックを抜けると自動で後始末処理が実行されます。
using System;
using System.IO;
using System.Linq;
class Program
{
public static void Main()
{
// 読み込むファイルのパス
string filePath = @"D:\test.exe";
// FileStreamのインスタンスを作成
using (var fs = File.OpenRead(filePath))
{
// ファイルの内容を入れるbyte配列を用意
byte[] bytes = new byte[fs.Length];
// バイナリファイルの読込 先頭(0)から末尾(fs.Length)まで
fs.Read(bytes, 0, (int)fs.Length);
// 先頭4バイトを表示(byteは0~255の数値)
Console.WriteLine(string.Join(" ", bytes.Take(4)));
} // ここで後始末(Close)の処理が実行される
}
}
バイナリファイルの内容を型を指定して読み込む
System.IO.BinaryReaderクラスを使うとバイナリのデータから型を指定して読み込むことが出来ます。
とりあえずサンプルです。
using System;
using System.IO;
class Program
{
public static void Main()
{
// 読み込むファイルのパス
string filePath = @"D:\test.exe";
// FileStreamのインスタンスを作成
using var fs = File.OpenRead(filePath);
// BinaryReaderのインスタンスを作成
var br = new BinaryReader(fs);
// 読込位置の表示、先頭は0
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
// int型で読み込み
Console.WriteLine($"int={br.ReadInt32()}");
// 読込位置の表示、int型のサイズ分進んだ
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
// byte型で読み込み
Console.WriteLine($"byte={br.ReadByte()}");
// 読込位置の表示、byte型のサイズ分進んだ
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
// byte[]型で読み込み
Console.WriteLine($"byte[10]={string.Join(" ", br.ReadBytes(10))}");
// 読込位置の表示、byte[]型のサイズ分進んだ
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
// double型で読み込み
Console.WriteLine($"double={br.ReadDouble()}");
// 読込位置の表示、double型のサイズ分進んだ
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
}
}
出力結果はこんな感じです。
読込位置=0
---------------------------
int=9460301
読込位置=4
---------------------------
byte=3
読込位置=5
---------------------------
byte[10]=0 0 0 4 0 0 0 255 255 0
読込位置=15
---------------------------
double=2.32725E-319
読込位置=23
---------------------------
使い方はわかったからもういいやという人はここで終わりです。
次からはサンプルコードの解説です。
サンプルコードの解説
BinaryReaderクラスを使うにはまずSystem.IO.FileOpenReadメソッドを使ってファイルを開く必要があります。このメソッドは引数で指定されたパスのファイルを読み取り専用で開きます。指定したファイルが存在しない場合はエラーになるので注意してください。
// FileStreamのインスタンスを作成
using var fs = File.OpenRead(filePath);
次にBinaryReaderのコンストラクターにOpenReadで作ったインスタンスを指定します。
// BinaryReaderのインスタンスを作成
var br = new BinaryReader(fs);
BinaryReaderインスタンスのReadInt32メソッドを使ってバイナリのデータをint型で読み込みます。
ReadInt32メソッドは現在の読込位置から4バイトのデータを取得してint型に変換します。そして読込位置を4バイト先に進めます。
読込位置はFileStreamクラスインスタンスのPositionプロパティで取得できます。0が先頭です。
Console.WriteLine($"読込位置={fs.Position}"); // 0(ファイルの先頭)
Console.WriteLine($"int={br.ReadInt32()}"); // 4バイト分(0~3バイト目)読み込んでintに変換
Console.WriteLine($"読込位置={fs.Position}"); // 4(次は4バイト目から読み込む)
BinaryReaderの読み込み用メソッド一覧
メソッド | 戻り値の型 | 読み込むバイト数 |
---|---|---|
ReadBoolean() | boolean | 1 |
ReadByte() | byte | 1 |
ReadBytes(読み込む数) | byte[] | 1 × 読み込む数 |
ReadChar() | char | 1文字(文字コードに依存) |
ReadChars(読み込む数) | char[] | 1文字(文字コードに依存) × 読み込む数 |
ReadDecimal() | decimal | 16 |
ReadDouble() | double | 8 |
ReadInt16() | short | 2 |
ReadInt32() | int | 4 |
ReadInt64() | long | 8 |
ReadSByte() | sbyte | 1 |
ReadSingle() | float | 4 |
ReadUInt16() | ushort | 2 |
ReadUInt32() | uint | 4 |
ReadUInt64() | ulong | 8 |
文字コードの指定
文字コードを指定する場合は、BinaryReaderのコンストラクターの第2引数に文字コードを指定します。
var br = new BinaryReader(fs, System.Text.Encoding.UTF8);
読込位置を移動する
現在の読込位置を変更するには、FileStreamクラスインスタンスのPositionプロパティに新しい位置を設定します。
using System;
using System.IO;
class Program
{
public static void Main()
{
// 読み込むファイルのパス
string filePath = @"D:\test.exe";
// FileStreamのインスタンスを作成
using var fs = File.OpenRead(filePath);
// BinaryReaderのインスタンスを作成
var br = new BinaryReader(fs);
// 読込位置を変更(10バイト目から)
fs.Position = 10;
Console.WriteLine($"読込位置={fs.Position}");
// int型で読み込み
Console.WriteLine($"int={br.ReadInt32()}");
// 読込位置の表示、int型のサイズ分進んだ
Console.WriteLine($"読込位置={fs.Position}");
Console.WriteLine("---------------------------");
}
}
読込位置=10
int=-65536
読込位置=14
---------------------------