メソッド追加 readFrom

次のC言語で作られたバイナリファイルがあるとします。(ファイルは16進ダンプした内容で示します)

#include <stdio.h>

typedef struct {
	char sho[4];	/* 商品コード */
	short suu;	/* 数量 */
} Record2;

main()
{
	Record2 recs[] = {
		{"A01" ,4},
		{"A01" ,5},
		{"A01" ,1},
		{"A03" ,5},
		{"B02" ,3},
		{"B02" ,9},	
		{"B03" ,10}		
	};
	FILE *fpw = fopen("transact0.bin", "wb");/* バイナリファイル生成 */
	int i;
	for(i=0; i < 7; i++){
		fwrite(recs+i , sizeof(Record2), 1, fpw);
	}
	fclose(fpw);
}
0000 41 30 31 00 04 00 41 30 31 00 05 00 41 30 31 00
0010 01 00 41 30 33 00 05 00 42 30 32 00 03 00 42 30
0020 32 00 09 00 42 30 33 00 0A 00

このファイルから1レコード分読み込むメソッドを、 readFromの名前でRecord2クラスに用意します。 (上記ファイルtransact0.bin)
まずどのように使えると便利かを検討します。次のように使えれば便利でしょう。 FileInputStreamの参考⇒(確認後はブラウザの戻る操作で戻ってください

import java.io.FileInputStream;

public class Test
{
	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("transact0.bin");
		int n = 1;
		Record2 rec = new Record2();
		rec.readFrom(fis);//レコード読み込み
		while(rec.sho.equals(Record2.HIGH_VALUE) == false){
			rec.display( n++ );
			rec.readFrom(fis);//レコード読み込み
		}
		fis.close();
	}
}

バイトのストリームを引数にし、一回のreadFromの実行で1レコードだけ読み込むメソッドにします。
そして、ファイル終端など、レコードのデータが無くなってからのreadFrom実行は、商品コードを データとして存在しないstaticフィールドのHIGH_VALUEを設定します。
よって、この値になるまでの読み込み繰り返しで、全てのレコードが読み込めます。
実行結果を以下に示します。

Z:\Java>java Test
   1番目レコード
        商品コード:A01
        数量:4
   2番目レコード
        商品コード:A01
        数量:5
   3番目レコード
        商品コード:A01
        数量:1
   4番目レコード
        商品コード:A03
        数量:5
   5番目レコード
        商品コード:B02
        数量:3
   6番目レコード
        商品コード:B02
        数量:9
   7番目レコード
        商品コード:B03
        数量:10

Z:\Java>

また、ファイル終端などのreadFrom実行で、falseを返すメソッドにすることで、次のような使い方もできるようにします。

import java.io.FileInputStream;

public class Test
{
	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream("transact0.bin");
		int n = 1;
		Record2 rec = new Record2();
		while(rec.readFrom(fis)){//終端でなければ繰り返し入力
			rec.display( n++ );
		}
		fis.close();
	}
}

以上の使い方ができるように、readFromメソッドをRecord2クラスに作成します。 一回の実行で、一つのレコード分を読み取ります。
一つのレコードは、上記C言語の構造体の出力で6バイトです。それは 例えば次のようなバイト列です。
41 30 31 00 04 00  これは、"A01" と 16bit整数の4 です。
次のように作成できます。 

	public boolean readFrom(FileInputStream fis)throws Exception{
		if (sho != null && sho.equals(Record2.HIGH_VALUE) == true){
			return false;
		}

		byte[] a = new byte[6];
		int n = fis.read(a);//6byte読み込み
		if (n != 6){
			sho = HIGH_VALUE;
			return false;
		}

		//4byteの3文字を連結して使う
		sho = "" + (char)a[0] + (char)a[1] + (char)a[2];

		//16ビット(2byte)整数として使う
		suu = (short)(0x0ff & a[5]);
		suu <<= 8;	// 1バイト分左シフト(256倍している)
		suu |= 0x0ff & a[4]; //ビットORで結合
		return true;
	}

以下にreadFromメソッドを実装したRecord2のクラス図を示します。

このクラスを利用して、コマンドラインで指定するファイルを表示する Rec2Read.javaのソースファイルと実行例を以下に示します。

import java.io.FileInputStream;

public class Rec2Read
{
	public static void main(String[] args) throws Exception {
		FileInputStream fis = new FileInputStream(args[0]);//コマンドラインパラメタのファイルストリームを得る
		int n = 1;
		Record2 rec = new Record2();
		while(rec.readFrom(fis)){//終端でなければ、1レコードを読む繰り返し入力
			rec.display(n++);//1レコードの表示
		}
		fis.close();
	}
}
D:\java>java Rec2Read transact0.bin
   1番目レコード
        商品コード:A01
        数量:4
   2番目レコード
        商品コード:A01
        数量:5
   3番目レコード
        商品コード:A01
        数量:1
   4番目レコード
        商品コード:A03
        数量:5
   5番目レコード
        商品コード:B02
        数量:3
   6番目レコード
        商品コード:B02
        数量:9
   7番目レコード
        商品コード:B03
        数量:10

D:\java>