トップ «前の日記(2010年11月04日) 最新 次の日記(2010年11月12日)» 編集

Masa's blog

検索キーワード:

2010年11月11日 Java儂(わし)的解釈によるメモ(マッチング処理編) [長年日記]

_ Java儂(わし)的解釈によるメモ(マッチング処理編)

いわゆるマッチング処理によるマスターファイル更新的なサンプルプログラム。

初めてJavaで業務処理(バッチ処理)的なものを実装。COBOLERパワー全開の芳ばしい一品にしあがっておる。

MasterRecord クラス

COBOLプログラムで言うところのレコード定義COPY原文に相当するのか。

ただし、あくまでもこれはクラスなので、レコードレイアウトの項目定義だけでなく、取り扱いに関する各種メソッドも実装する。

//
// レコードクラス
//
//   業務ファイルのレイアウト毎に色々と定義されるであろうクラス
//
class MasterRecord {
	//
	// 項目定義
	//
	int id;
	String name;
	String job;
	//
	// コンストラクタ(生成時の初期化処理)
	//
	MasterRecord() {
		initialize();
	}
	//
	// 初期化処理
	//
	void initialize() {
		id = 0;
		name = null;
		job = null;
	}
	//
	// TAB区切りレコードから項目に取り込み
	//
	String set(String record) {
		if (record != null){
			String[] array = record.split("\t");
			id = Integer.valueOf(array[0]);
			name = array[1];
			job = array[2];
		}
		return record;
	}
	//
	// 項目からTAB区切りレコードを取得
	//
	String get() {
		return String.format("%d\t%s\t%s", id, name, job);
	}
	//
	// 各項目に値を設定
	//
	void setId(int id) {
		this.id = id;
	}
	void setName(String name) {
		this.name = name;
	}
	void setJob(String job) {
		this.job = job;
	}
	//
	// 各項目の値を取得
	//
	int getId() {
		return id;
	}
	String getName() {
		return name;
	}
	String getJob() {
		return job;
	}
}

TextFile クラス

レコードが改行文字で終端するファイル(いわゆるテキストファイル)を取り扱うためのクラス。

import java.io.*;
//
// テキストファイルクラス
//
class TextFile {
	String file_name;
	String mode;
	String encoding;
	BufferedReader br;
	BufferedWriter bw;
	long read_count;
	long write_count;
	//
	// コンストラクタ
	//
	TextFile() {
		file_name = null;
		mode = null;
		encoding = "EUC-JP";
		br = null;
		bw = null;
		read_count = 0;
		write_count = 0;
	}
	//
	// open(1)
	//
	// 	String file_name	ファイル名称
	// 	String mode		オープンモード("r"|"w"|"a")
	// 	ファイルのエンコーディングはコンストラクタでの設定になります
	//
	//	戻り値	正常 : true
	//		異常 : false
	//
	boolean open(String file_name, String mode) throws Exception {
		this.file_name = file_name;
		this.mode = mode;

		read_count = 0;
		write_count = 0;

		if (mode.equals("r")){
			br = new BufferedReader(
				new InputStreamReader(
					new FileInputStream(file_name),
					encoding
				)
			);
		}else if(mode.equals("w")|mode.equals("a")){
			bw = new BufferedWriter(
				new OutputStreamWriter(
					new FileOutputStream(file_name, (mode.equals("a") ? true : false)),
					encoding
				)
			);
		}else{
			return false;
		}
		return true;
	}
	//
	// open(2)
	//
	// 	String file_name	ファイル名称
	// 	String mode		オープンモード("r"|"w"|"a")
	//	String encoding		エンコーディング
	//
	//	戻り値	正常 : true
	//		異常 : false
	//
	boolean open(String file_name, String mode, String encoding) throws Exception {
		this.file_name = file_name;
		this.mode = mode;
		this.encoding = encoding;
		return open(file_name, mode);
	}
	//
	// 一行読み込み
	//
	//	戻り値	正常 : レコード
	//		終了 : null
	//
	String read() throws Exception {
		String record;
		if ((record = br.readLine()) != null){
			read_count++;
		}
		return record;
	}
	//
	// 一行書き込み
	//
	//	record	書き込むレコード(改行含めない)
	//
	void write(String record) throws Exception {
		bw.write(record);
		bw.newLine();
		write_count++;
	}
	//
	// close
	//
	void close() throws Exception {
		read_count = 0;
		write_count = 0;

		if (br != null){
			br.close();
			br = null;
		}
		if (bw != null){
			bw.close();
			bw = null;
		}
	}
	//
	// flush
	//
	void flush() throws Exception {
		if (bw != null){
			bw.flush();
		}
	}
	//
	// 読み込み件数取得
	//
	long getReadCount(){
		return read_count;
	}
	//
	// 書き込み件数取得
	//
	long getWriteCount(){
		return write_count;
	}
}

CsvTest.java メインクラス

情報処理試験にでも出てきそうなマッチング処理によるマスタファイル更新処理。

いちおうCURDを実装している。

//
// マスターファイルをトランザクションファイルで更新した結果を出力する処理
//
// 	マスター(入力) TAB区切りファイル
// 		int	id	(昇順)
// 		String	name
// 		String	job
//
// 	トランザクション(入力) TAB区切りファイル
// 		int	kbn	0:削除, 1:追加, 2:修正
// 		int	id	(昇順)
// 		String	name
// 		String	job
//
// 	更新後マスター(出力) TAB区切りファイル
// 		int	id	(昇順)
// 		String	name
// 		String	job
//
// 	(1) マスタファイルとトランザクションファイルをidで1対1のマッチングを行う
// 	(2) マッチングした場合はトランザクションファイルのデータを出力する
// 	(3) マスターファイルのみ有りのデータはそのまま出力する
// 	(4) トランザクションファイルのみ有りのデータは廃棄する
//
// 定数クラス
//
class Constant {
	String PGMNAME = "CsvTest";
	String DEF_MASTFILENAME = "CsvTest_mast.txt";
	String DEF_TRANFILENAME = "CsvTest_tran.txt";
	String DEF_OUTFILENAME = "CsvTest_out.txt";
	String DEF_ENCODING = "EUC-JP";
	int KBN_DELETE = 0;
	int KBN_INSERT = 1;
	int KBN_UPDATE = 2;
}
//
// トランザクションレコードクラス
//
class MasterRecordTran extends MasterRecord {
	int kbn;

	MasterRecordTran() {
		kbn = 0;
	}

	void initialize() {
		super.initialize();
		kbn = 0;
	}

	String set(String record) {
		if (record != null){
			String[] array = record.split("\t", 2);
			kbn = Integer.valueOf(array[0]);
			super.set(array[1]);
		}
		return record;
	}

	String get() {
		return String.format("%d\t%s", kbn, super.get());
	}

	int getKbn() {
		return kbn;
	}

	void setKbn(int kbn) {
		this.kbn = kbn;
	}
}
//
// スイッチクラス
//
class Switch {
	boolean state;
	Switch(){
		state = false;
	}
	Switch(boolean state){
		this.state = state;
	}
	void on(){
		state = true;
	}
	void off(){
		state = false;
	}
	boolean is_on(){
		return (state == true);
	}
	boolean is_off(){
		return (state == false);
	}
}
//
// メインクラス
//
class CsvTest {
	//
	// 定数オブジェクト
	//
	Constant cs = new Constant();
	//
	// マスターファイル&レコードオブジェクト
	//
	TextFile mastFile = new TextFile();
	MasterRecord mastRec = new MasterRecord();
	//
	// トランザクションファイル&レコードオブジェクト
	//
	TextFile tranFile = new TextFile();
	MasterRecordTran tranRec = new MasterRecordTran();
	//
	// 出力ファイル&レコードオブジェクト
	//
	TextFile outFile = new TextFile();
	MasterRecord outRec = new MasterRecord();
	//
	// 処理終了スイッチ
	//
	Switch endSw = new Switch();
	//
	// メイン処理
	//
	public static void main(String[] args) throws Exception {
		CsvTest m = new CsvTest();
		try {
			m.openProc();		// オープン処理
			m.initProc();		// 初期処理
			while (m.endSw.is_off()){
				m.mainProc();	// 主処理
			}
			m.endProc();		// 終了処理
		}catch (Exception e){
			System.out.println(m.cs.PGMNAME + " : 例外エラーが発生したので強制終了します : " + e);
		}finally{
			m.closeProc();		// クローズ処理
		}
	}
	//
	// オープン処理
	//
	void openProc() throws Exception {
		//
		// マスターオープン
		//
		mastFile.open(cs.DEF_MASTFILENAME, "r", cs.DEF_ENCODING);
		//
		// トランザクションオープン
		//
		tranFile.open(cs.DEF_TRANFILENAME, "r", cs.DEF_ENCODING);
		//
		// 更新後マスターオープン
		//
		outFile.open(cs.DEF_OUTFILENAME, "w", cs.DEF_ENCODING);
	}
	//
	// 初期処理
	//
	void initProc() throws Exception {
		System.out.println(cs.PGMNAME + " : マスター更新処理 開始");
		//
		// マスター読み込み
		//
		readMast();
		//
		// トランザクション読み込み
		//
		readTran();
		//
		// 終了判断
		//
		setEndSw();
	}
	//
	// 主処理
	//
	void mainProc() throws Exception {
		if (mastRec.getId() == tranRec.getId()){
			//
			// マッチした場合
			//
			if (tranRec.getKbn() == cs.KBN_DELETE){
				// do nothing
			}else if (tranRec.getKbn() == cs.KBN_INSERT){
				System.out.println("既にデータが存在するので追加できません : " + tranRec.get());
				outRec.set(mastRec.get());
				writeOut();
			}else if (tranRec.getKbn() == cs.KBN_UPDATE){
				editOutRec();
				writeOut();
			}else{
				System.out.println("処理区分が不正なので処理できません : " + tranRec.get());
				outRec.set(mastRec.get());
				writeOut();
			}
			readMast();
			readTran();
		}else if (mastRec.getId() > tranRec.getId()){
			//
			// トランザクションのみの場合(又は更新済みの場合)
			//
			if (tranRec.getKbn() == cs.KBN_DELETE){
				System.out.println("削除データが存在しないので削除できません : " + tranRec.get());
			}else if (tranRec.getKbn() == cs.KBN_INSERT){
				editOutRec();
				writeOut();
			}else if (tranRec.getKbn() == cs.KBN_UPDATE){
				System.out.println("更新データが存在しないので更新できません : " + tranRec.get());
			}else{
				System.out.println("処理区分が不正かつ対象データが存在しないので処理できません : " + tranRec.get());
			}
			readTran();
		}else{
			//
			// マスターのみの場合
			//
			outRec.set(mastRec.get());
			writeOut();
			readMast();
		}
		setEndSw();
	}
	//
	// 終了処理
	//
	void endProc() throws Exception {
		System.out.println(cs.PGMNAME + " : マスター更新処理 終了");
	}
	//
	// クローズ処理
	//
	void closeProc() throws Exception {
		mastFile.close();
		tranFile.close();
		outFile.close();
	}
	//
	// マスター読み込み
	//
	void readMast() throws Exception {
		if (mastRec.set(mastFile.read()) == null){
			mastRec.setId(Integer.MAX_VALUE);
		}
	}
	//
	// トランザクション読み込み
	//
	void readTran() throws Exception {
		if (tranRec.set(tranFile.read()) == null){
			tranRec.setId(Integer.MAX_VALUE);
		}
	}
	//
	// 更新後マスターファイル書き込み
	//
	void writeOut() throws Exception {
		outFile.write(outRec.get());
	}
	//
	// 終了判断
	//
	void setEndSw() throws Exception {
		if (mastRec.getId() == Integer.MAX_VALUE &&
		    tranRec.getId() == Integer.MAX_VALUE){
			endSw.on();
		}
	}
	//
	// 更新後マスターレコード編集
	//
	void editOutRec(){
		outRec.initialize();
		outRec.setId(tranRec.getId());
		outRec.setName(tranRec.getName());
		outRec.setJob(tranRec.getJob());
	}
}

CsvTest.java 実行結果(正常終了)

$ head -20 CsvTest_mast.txt CsvTest_tran.txt
==> CsvTest_mast.txt <==
10      氏名10  職業10
11      氏名11  職業11
20      氏名20  職業20
21      氏名21  職業21
30      氏名30  職業30
31      氏名31  職業31

==> CsvTest_tran.txt <==
2       10      氏名10T 職業10T
0       11      氏名11T 職業11T
0       15      氏名15T 職業15T
1       16      氏名16T 職業16T
2       17      氏名17T 職業17T
3       18      氏名18T 職業18T
2       21      氏名21T 職業21T
0       25      氏名25T 職業25T
1       26      氏名26T 職業26T
2       27      氏名27T 職業27T
1       30      氏名30T 職業30T
4       31      氏名31T 職業31T
$ java CsvTest
CsvTest : マスター更新処理 開始
CsvTest : 削除データが存在しないので削除できません : 0    15      氏名15T 職業15T
CsvTest : 更新データが存在しないので更新できません : 2    17      氏名17T 職業17T
CsvTest : 処理区分が不正かつ対象データが存在しないので処理できません : 3  18      氏名18T 職業18T
CsvTest : 削除データが存在しないので削除できません : 0    25      氏名25T 職業25T
CsvTest : 更新データが存在しないので更新できません : 2    27      氏名27T 職業27T
CsvTest : 既にデータが存在するので追加できません : 1      30      氏名30T 職業30T
CsvTest : 処理区分が不正なので処理できません : 4  31      氏名31T 職業31T
CsvTest : マスター更新処理 終了
$ head -20 CsvTest_out.txt
10      氏名10T 職業10T
16      氏名16T 職業16T
20      氏名20  職業20
21      氏名21T 職業21T
26      氏名26T 職業26T
30      氏名30  職業30
31      氏名31  職業31
$

CsvTest.java 実行結果(異常終了)

$ head -20 CsvTest_mast.txt CsvTest_tran.txt
==> CsvTest_mast.txt <==
10      氏名10  職業10
11      氏名11  職業11
20      氏名20  職業20
21      氏名21  職業21
30      氏名30  職業30
31      氏名31  職業31

==> CsvTest_tran.txt <==
2       10      氏名10T 職業10T
0       11      氏名11T 職業11T
0       15      氏名15T 職業15T
1       16      氏名16T 職業16T
2       17      氏名17T 職業17T
3       1B      氏名18T 職業18T
2       21      氏名21T 職業21T
0       25      氏名25T 職業25T
1       26      氏名26T 職業26T
2       27      氏名27T 職業27T
1       30      氏名30T 職業30T
4       31      氏名31T 職業31T
$ java CsvTest
CsvTest : マスター更新処理 開始
CsvTest : 削除データが存在しないので削除できません : 0    15      氏名15T 職業15T
CsvTest : 更新データが存在しないので更新できません : 2    17      氏名17T 職業17T
CsvTest : 例外エラーが発生したので強制終了します : java.lang.NumberFormatException: For input string: "1B"
$  head -20 CsvTest_out.txt
==> CsvTest_out.txt <==
10      氏名10T 職業10T
16      氏名16T 職業16T
$