バイナリファイルの読み書き。PNG の縦横サイズを取得してみる

BinaryReader, BinaryWriter クラスを用いて、バイナリデータの読み書きを行うサンプルです。

using System;
using System.IO;

class Program {
    const string filename = "data.dat";

    static void Read() {
        using (var reader = new BinaryReader(File.Open(filename, FileMode.Open))) {
            int x = reader.ReadInt32();
            char c1 = reader.ReadChar();
            char c2 = reader.ReadChar();

            Console.WriteLine("x: 0x{0:X}", x);
            Console.WriteLine("c1: {0}", c1);
            Console.WriteLine("c2: {0}", c2);
        }
    }

    static void Write() {
        using (var writer = new BinaryWriter(File.Open(filename, FileMode.Create))) {
            writer.Write(0x11FF33cc);
            writer.Write('a');
            writer.Write('あ');
        }
    }

    static void Main() {
        Write();
        Read();
    }
}

実行結果です。

x: 0x11FF33CC
c1: a
c2: あ

hexdump コマンドで作成したファイルの中身を確認してみます。

$ hexdump data.dat
0000000 cc 33 ff 11 61 e3 81 82
0000008

PNG ファイルの縦横サイズを取得してみる

PNGについて のページには、PNG のファイルフォーマットの解説があります。

ここでは BinaryReader クラスを用いて、PNG ファイルの縦横サイズを取得してみます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

class Program {
    // BinaryReader の ReadInt32() はリトルエンディアンで読み込むので自作する
    static int Read32(BinaryReader reader) {
        int x = 0;
        for (int i = 0; i < 4; i++) {
            var b = reader.ReadByte();
            x = (x << 8) | b;
        }
        return x;
    }

    // bytes バイト分読み込む
    static byte[] Eat(int bytes, BinaryReader reader) {
        var ret = new byte[bytes];
        for (int i = 0; i < bytes; i++) {
            ret[i] = reader.ReadByte();
        }
        return ret;
    }

    static void Read(string filename) {
        using (var reader = new BinaryReader(File.Open(filename, FileMode.Open))) {
            // PNG 識別部
            var png = Eat(8, reader);
            Console.WriteLine("PNG 識別部");
            Console.WriteLine(string.Join(" ", png.Select(e => string.Format("0x{0:X}", e))));

            // --- 本体部 ----

            Read32(reader); // データ長

            // 名称
            var name = Eat(4, reader);
            Console.WriteLine(string.Join("", name.Select(e => (char)e)));

            // IHDR が一番最初に必ず存在する
            int width = Read32(reader);
            int height = Read32(reader);
            Console.WriteLine("width  = {0}", width);
            Console.WriteLine("height = {0}", height);
        }
    }

    static void Main() {
        Read("test.png"); // 横 320 縦 60 の画像を読み込む
    }
}

4 バイトのデータ長を取得するときに、BinaryReader クラスの ReadInt32() メソッドではなく自作の Read32() メソッドを使用しています。これは、ReadInt32() メソッドはリトルエンディアンで読み込むためです。

実行結果です。

PNG 識別部
0x89 0x50 0x4E 0x47 0xD 0xA 0x1A 0xA
IHDR
width  = 320
height = 60

リンク