C#でバイナリファイルを読み書きする方法|FileStream・BinaryReaderの使い方をサンプルコードで解説

はじめに

C#でファイル操作を行う際、テキストファイルだけでなく、画像や音声、独自フォーマットのデータなどを扱うためにはバイナリファイルの読み書きが必要です。本記事では、C#におけるバイナリファイル操作の基本から応用まで、FileStreamBinaryReaderBinaryWriterを使った具体的なサンプルコードを交えて解説します。初心者でも理解できるよう、ステップごとに丁寧に説明します。


1. C#で扱うバイナリファイルとは

1-1. バイナリファイルとテキストファイルの違い

バイナリファイルは文字コードではなく0と1の並びでデータを格納します。テキストファイルは文字として読み書きできるのに対し、バイナリファイルは数値や画像、音声など任意の形式のデータを効率よく保存できます。

1-2. バイナリファイルを読み書きする主な用途

  • 画像・音声・動画ファイルの操作

  • 独自フォーマットのデータ保存

  • 高速な数値計算結果の格納

  • ネットワーク通信でのデータ送受信

1-3. C#でバイナリファイル操作に使う代表的なクラス

C#では主に以下のクラスを使用します。

  • FileStream:ファイルの読み書き全般を低レベルで操作

  • BinaryReader:バイト単位や型ごとにデータを読み込む

  • BinaryWriter:バイト単位や型ごとにデータを書き込む

1-4. FileStream・BinaryReader・BinaryWriterの役割の違い

  • FileStream:ストリームとしてファイルにアクセス

  • BinaryReader:FileStreamから型付きデータを安全に読み込む

  • BinaryWriter:FileStreamに型付きデータを書き込む


2. C#でバイナリファイルを読み書きする基本手順

2-1. System.IO名前空間を使用する

バイナリファイル操作はSystem.IO名前空間に含まれるクラスを使用します。

C#
using System.IO;

2-2. FileStreamでファイルを開く

C#
FileStream fs = new FileStream("sample.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite);

2-3. BinaryReaderでデータを読み込む

C#
using (BinaryReader reader = new BinaryReader(fs))
{
int number = reader.ReadInt32();
}

2-4. BinaryWriterでデータを書き込む

C#
using (BinaryWriter writer = new BinaryWriter(fs))
{
writer.Write(1234);
}

2-5. using文でファイルを安全に閉じる

using文を使うと、ファイルが自動的に閉じられ、リソースリークを防げます。


3. FileStreamを使ってバイナリファイルを読み込む方法

3-1. FileStreamの基本構文

C#
FileStream fs = new FileStream("file.bin", FileMode.Open, FileAccess.Read);

3-2. FileMode・FileAccess・FileShareの指定方法

  • FileMode.Open:既存ファイルを開く

  • FileAccess.Read:読み取り専用

  • FileShare.ReadWrite:他プロセスと共有

3-3. Readメソッドでbyte配列に読み込むサンプルコード

C#
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);

3-4. ファイルサイズを取得して全バイトを読み込む方法

C#
long size = fs.Length;
byte[] data = new byte[size];
fs.Read(data, 0, data.Length);

3-5. 大きなバイナリファイルを分割して読み込む方法

C#
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
{
// 読み込んだデータを処理
}

4. BinaryReaderを使ってバイナリデータを読み込む方法

4-1. BinaryReaderの基本構文

C#
using (BinaryReader reader = new BinaryReader(fs))
{
// 読み込み処理
}

4-2. ReadByte・ReadBytesでバイト単位に読み込む

C#
byte singleByte = reader.ReadByte();
byte[] bytes = reader.ReadBytes(10);

4-3. ReadInt32・ReadDouble・ReadStringで型ごとに読み込む

C#
int number = reader.ReadInt32();
double value = reader.ReadDouble();
string text = reader.ReadString();

4-4. 読み込み位置をSeekで移動する方法

C#
reader.BaseStream.Seek(0, SeekOrigin.Begin); // ファイル先頭に戻す

4-5. EndOfStreamや例外を考慮した安全な読み込み方法

C#
while (reader.BaseStream.Position < reader.BaseStream.Length)
{
int data = reader.ReadInt32();
}

5. BinaryWriterを使ってバイナリファイルに書き込む方法

5-1. BinaryWriterの基本構文

C#
using (BinaryWriter writer = new BinaryWriter(fs))
{
writer.Write(100);
}

5-2. byte配列を書き込むサンプルコード

C#
byte[] bytes = { 1, 2, 3, 4 };
writer.Write(bytes);

5-3. int・double・stringなど複数の型を書き込む方法

C#
writer.Write(123);
writer.Write(3.14);
writer.Write("Hello");

5-4. 既存ファイルへ上書き・追記する方法

  • 上書き:FileMode.Create

  • 追記:FileMode.Append

5-5. 書き込んだデータをBinaryReaderで読み戻して確認する方法

C#
fs.Seek(0, SeekOrigin.Begin);
using (BinaryReader reader = new BinaryReader(fs))
{
int readValue = reader.ReadInt32();
}

6. FileStreamだけでバイナリファイルを読み書きする方法

6-1. FileStream.Writeでbyte配列を書き込む

C#
byte[] data = { 10, 20, 30 };
fs.Write(data, 0, data.Length);

6-2. FileStream.Readでbyte配列を読み込む

C#
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);

6-3. BinaryReader・BinaryWriterを使う場合との違い

  • FileStream単体は型情報を扱えない

  • BinaryReader/Writerは型ごとの読み書きが可能

6-4. byte配列だけを扱う場合にFileStreamが向いている理由

  • 型変換不要で直接操作できる

  • 大容量データの高速処理に適している


7. C#でバイナリファイルを読み書きする実践サンプル

7-1. 数値データをバイナリファイルに保存するサンプル

C#
int[] numbers = { 10, 20, 30 };
using (BinaryWriter writer = new BinaryWriter(File.Open("numbers.bin", FileMode.Create)))
{
foreach (var n in numbers)
writer.Write(n);
}

7-2. 保存した数値データを読み込むサンプル

C#
using (BinaryReader reader = new BinaryReader(File.Open("numbers.bin", FileMode.Open)))
{
while (reader.BaseStream.Position < reader.BaseStream.Length)
Console.WriteLine(reader.ReadInt32());
}

7-3. 画像や任意ファイルをbyte配列としてコピーするサンプル

C#
byte[] imageData = File.ReadAllBytes("image.png");
File.WriteAllBytes("copy.png", imageData);

7-4. 独自フォーマットのバイナリファイルを作成するサンプル

C#
using (BinaryWriter writer = new BinaryWriter(File.Open("custom.bin", FileMode.Create)))
{
writer.Write("Header");
writer.Write(12345);
}

7-5. ヘッダー情報とデータ本体を分けて読み書きするサンプル

C#
using (BinaryWriter writer = new BinaryWriter(File.Open("data.bin", FileMode.Create)))
{
writer.Write("HEADER"); // ヘッダー
writer.Write(new byte[] { 1, 2, 3, 4 }); // データ本体
}

8. バイナリファイル操作でよくあるエラーと対処法

8-1. ファイルが見つからない場合の対処

  • FileNotFoundExceptionをキャッチ

  • ファイルパスを確認

8-2. ファイルが使用中で開けない場合の対処

  • FileShareオプションを確認

  • 他プロセスで開かれていないかチェック

8-3. 読み込みサイズが不足する場合の対処

  • BaseStream.Lengthでサイズを確認

  • 必要なバイト数を確保して読み込む

8-4. データ型や読み込み順を間違えた場合の対処

  • 書き込み順と読み込み順を一致させる

  • 型ごとに正しく読み込む

8-5. 文字列のエンコーディングに注意する

  • BinaryWriterはUTF-8で書き込む

  • 他のエンコーディングで読み込みたい場合は変換が必要


9. バイナリファイル操作の注意点とベストプラクティス

9-1. using文でリソース解放を徹底する

  • 自動でファイルを閉じる

  • リソースリークを防ぐ

9-2. 読み込み順と書き込み順を一致させる

  • 型ごとの順序を守る

  • 読み込み時の例外を防ぐ

9-3. 大容量ファイルでは一括読み込みを避ける

  • 分割読み込みでメモリ消費を抑える

  • ReadReadBytesを活用

9-4. 例外処理でファイル破損やアクセス権限エラーに備える

  • try-catchで例外処理

  • エラー時にバックアップを作る

9-5. バイナリデータの中身を確認するデバッグ方法

  • Hexエディタで直接確認

  • デバッグ用にbyte配列を表示


10. C#のバイナリファイル操作でよくある質問

10-1. File.ReadAllBytesとの違いは何か

  • File.ReadAllBytesは一括読み込み専用

  • 大容量ファイルではFileStreamの方が効率的

10-2. BinaryReaderとFileStreamはどちらを使うべきか

  • 型付きデータならBinaryReader

  • byte単位の大量データならFileStream

10-3. バイナリファイルを構造体として読み込めるか

  • MarshalBinaryFormatterで可能

  • 型のサイズと順序に注意

10-4. テキストファイルをバイナリとして読み込めるか

  • 可能だが、文字コードに注意

  • UTF-8などで文字化けする場合あり

10-5. .NET Frameworkと.NETで書き方は違うか

  • 基本は同じ

  • 新しい.NETではFileStreamBinaryReaderの拡張機能あり


まとめ

C#でのバイナリファイル操作は、FileStreamを基盤としてBinaryReaderBinaryWriterを組み合わせることで、安全かつ効率的に実現できます。型ごとの読み書きやファイル分割、大容量データの扱い方を理解すれば、画像や独自フォーマットのデータも自在に操作可能です。using文や例外処理を徹底することで、ファイル破損やメモリリークを防ぎながら、堅牢なプログラムを作ることができます。