バイナリファイルの読み書き

バイナリとは

パソコンで扱うファイルには大きく分けてテキストファイルバイナリファイルの二種類が存在します。
テキストファイルの中身は日本語や英語などで書かれた文書で、人間が読み書きできるファイルです。
一方でバイナリファイルは、(普通の)人間にはそのまま読み書きできないファイルです。

パソコンはすべてのデータを0か1の二進数で扱います。
画像ファイルも音楽ファイルも内部的にはすべて0と1の羅列です。
バイナリとはこのような二進数で表されたデータを指します。
(binary: 2の、二進法の、という意味)

バイナリデータは人間が直接読み書きするためのものではなく、プログラムが読み書きするためのものです。
例えば画像ビューアで画像ファイルを読み込めば、写真やイラストを表示することができます。

細かいことを言えばテキストファイルも内部的には二進数で表現されているのでバイナリファイルといえますが、テキストファイルは「文字として表せるデータのみ」を使用できるフォーマットです。
通常「バイナリファイル」とは、文字として扱えないその他のデータが含まれるものを言います。

ファイルというのは他のプログラムからも使用されることがあるので、ファイル操作は比較的エラーの起きやすい処理です。
何らかの理由で読み書きに失敗した場合はエラー(例外)が発生します。

以下のサンプルコードはエラー処理は省いています。
エラーに適切に対処するには例外を参照してください。

バイナリファイルの書き込み

バイナリデータをファイルに書き込むにはFile.WriteAllBytesメソッドを使用します。


using System;
using System.IO;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string path = "test.png";

            byte[] binary = new byte[] 
                { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x18, 0xED, 0xA3, 0x00, 0x00, 0x00, 0x2A, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xEC, 0xCD, 0x41, 0x0D, 0x00, 0x00, 0x08, 0x04, 0xA0, 0xD3, 0xFE, 0x9D, 0x35, 0x85, 0x0F, 0x37, 0x28, 0x40, 0x4D, 0x6E, 0x75, 0x04, 0x02, 0x81, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0xC1, 0x93, 0x60, 0x05, 0x18, 0x00, 0xA3, 0xC4, 0x01, 0x3F, 0xD1, 0xCC, 0x8C, 0x55, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };

            //バイナリデータの書き込み
            File.WriteAllBytes(path, binary);

            Console.WriteLine("{0}に書き込みました。", path);
            Console.ReadLine();
        }
    }
}

バイナリデータはC#のコード上ではbyte型の配列で扱います。

「0x00」というのは16進数を表します。
(16進数リテラル参照)
二進数を0と1で表記すると桁数が多くなりすぎるため、プログラミングでは16進数で扱うことが良くあります。

このバイナリデータはPNG画像ファイルです。
上記コードを実行すると実行ファイルと同じフォルダ内に「test.png」というファイルが生成されます。
適当な画像ビューアで開くと赤で塗りつぶされた小さな画像が表示されるはずです。

バイナリファイルの出力テスト

バイナリファイルの読み込み

バイナリファイルを読み込むにはFile.ReadAllBytesメソッドを使用します。


string path = "test.png";

byte[] binary = new byte[] 
    { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x02, 0x00, 0x00, 0x00, 0xFC, 0x18, 0xED, 0xA3, 0x00, 0x00, 0x00, 0x2A, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xEC, 0xCD, 0x41, 0x0D, 0x00, 0x00, 0x08, 0x04, 0xA0, 0xD3, 0xFE, 0x9D, 0x35, 0x85, 0x0F, 0x37, 0x28, 0x40, 0x4D, 0x6E, 0x75, 0x04, 0x02, 0x81, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0xC1, 0x93, 0x60, 0x05, 0x18, 0x00, 0xA3, 0xC4, 0x01, 0x3F, 0xD1, 0xCC, 0x8C, 0x55, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };

//バイナリデータの書き込み
File.WriteAllBytes(path, binary);
Console.WriteLine("{0}に書き込みました。", path);

//バイナリデータの読み込み
byte[] binaryRead = File.ReadAllBytes(path);

Console.WriteLine("{0}の内容", path);
for (int i = 0; i < binaryRead.Length; i++)
{
    Console.Write("0x{0:X2}, ", binaryRead[i]);
}

戻り値はbyte型配列です。

長くなるので実行結果は省略しますが、書き込んだデータと一致するはずです。

WriteLineメソッドの16進数表記についてはstring.Formatメソッド十六進数の項を参照してください。

バイナリデータの詳細な編集

上記の方法でバイナリファイルの読み書きは可能ですが、これだけではあまり実用的ではありません。
数値や文字列などのデータをバイナリデータと相互変換するにはまた別の機能を使用する必要があります。
その方法は別の機会に説明します。

数値や文字列とバイナリデータの相互変換はbyte型配列との相互変換BinaryReader/Writerを参照してください。
クラスをバイナリに変換するにはBinaryFormatterクラスを参照してください。