第7講:「ClassTableWriter」を拡張する

その1 「ClassTableWriter」を拡張してテキストファイルからの入力による「時間割」の作成を可能にする

 ここでは「ClassTableWriter」を完全版「時間割表示システム」に対応できるように拡張します。そのためには、まずはじめ扱うデータを「1日分の時間割」から(1週間分の)「時間割」に変更する必要があります。ここでは「時間割」のプログラム上での表現方法とその利用法を解説します。つぎに、データの入力先をキーボードからテキストファイルへと変更します。そのほうがユーザーにとってデータファイルを作成しやすいからです。ここではあらかじめ用意されたテキストファイルを読み込む方法を学習します。それらを学んだ後に、実際のプログラムの書き換えを行います。

(1)「時間割」の表現方法とその利用法

 完全版「時間割表示システム」の扱うデータは<時間割>です。第2講で行った定義によると、<時間割>とは<1日分の時間割>5つの集合体のことでした。

 この<時間割>をプログラム上で表現するにあたっては、<1日分の時間割>と同様にVectorを用いることにします。すなわち<時間割>用のVectorを一つ用意し、その中に以下の図のように<1日分の時間割>を5つ格納するわけです。
時間割

0

1日分の時間割

1

1日分の時間割

2

1日分の時間割

3

1日分の時間割

4

1日分の時間割

 Vectorはどのようなクラスのインスタンスでも格納できます。Vectorクラスのインスタンスを格納することも可能です。ここに格納されているそれぞれの<1日分の時間割>には、いままでのように<授業の情報>が5つ格納されています。
1日分の時間割

0

授業の情報

1

授業の情報

2

授業の情報

3

授業の情報

4

授業の情報

 このとき、時間割Vectorの部屋番号(「インデックス」と呼ばれる)の0〜4は月曜日〜金曜日に、1日分の時間割Vectorのインデックス0〜4はそれぞれ1時限目〜5時限目という風に、インデックスと格納されるデータの順序にきちんとした対応関係が成り立つようにしてあれば、後々のデータの利用が非常にうまくゆきます。

 この<時間割>を作成するための手順は、<1日分の時間割>のそれを応用します。全体を示せば以下のようになるでしょう。

1)<時間割>を格納するVectorを用意する

2)「繰り返し文」を用い、以下の命令を5回繰り返す

1 <1日分の時間割>の作成

2 作成された<1日分の時間割>を<時間割>に格納

このとき、<1日分の時間割>の作成は、従来の方法(「繰り返し文」を利用して5つの<授業の情報>を<1日分の時間割>のVectorに収める)をそのまま当てはめればよいのです。

 またデータの利用の際には、先程述べたインデックスとデータの秩序の対応関係をうまく利用し、「elementAt」メソッドによって情報を取り出してくればよいのです。例えば「金曜、3限」の<授業の情報>を必要とする場合には、以下の手順で取り出せばよいのです。仮に<授業の情報>Vectorのインスタンス名を「week」とすると、

Vector day = (Vector)week.elementAt( 4 ); //「金曜日」の<1日の時間割>の取り出し

ClassTable ct = (ClassTable)day.elementAt(2); //「3限」の<授業の情報>の取り出し

こうすれば「ct」には「金曜、3限」の<授業の情報>が代入されます。

(2)テキストファイルを読み込む方法

 これまでは「1日分の時間割」を作成するために、それを構成する「授業の情報」のひとつひとつをキーボードから入力する必要がありました。もしもこれを1日分ではなく、1週間分の「時間割」に拡張する場合、この方式でデータを入力するのは大変です(例えばタイプミスをした場合、現在のClassTableWriterでは変更がききません)。そこで、あらかじめ1週間分の「授業の情報」として必要な事項をテキストファイルで作成・保存しておき、キーボードの代わりにそのファイルを入力先として、データの入力を行えると非常に便利になります。

 そこで、以下のようなテキストファイルの内容を読み込む方法を紹介します。
1			←月曜1限の「時限」
情報解析法		←月曜1限の「科目名」
t12			←月曜1限の「教室名」
2			←月曜2限の「時限」
概念構築法		←月曜2限の「科目名」
t12			←月曜2限の「教室名」

		




4			←金曜4限の「時限」
国際協力論		←金曜4限の「科目名」
t11			←金曜4限の「教室名」
5			←金曜5限の「時限」
なし			←金曜5限の「科目名」
なし			←金曜5限の「教室名」

 用意するテキストファイルには、以上のように月曜1限から金曜5限に至る「授業の情報」を、「時限、改行、科目名、改行、教室名、改行」と各項目に必ず改行を挟みながら入力しておきます。そして、このテキストファイルからデータの入力を行えるよう「ClassTableWriter」を作り直します。

前回作成した「旧型」ClassTableWriter
キーボードから
「1日分の時間割」を入力 →
処理
→ データファイル
「Day.data」を出力

今回作成する「新型」ClassTableWriter
テキストファイルから
(1週間分の)「時間割」を入力 →
処理
→ データファイル
「Week.data」を出力

 キーボード入力をテキストファイル入力に変更するためには「BufferedReader」のインスタンス化の際の記述を以下のように変更します。

キーボード入力準備の際の、「BufferedReader」インスタンス化の記述:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

テキストファイル入力準備の際の、「BufferedReader」インスタンス化の記述:
BufferedReader reader = new BufferedReader(new FileReader(" file name "));

 「BufferedReader」は文字列型のデータを1行読み込む「readLine」というメソッドを持っていました。これまでの説明では、インスタンス化の際の()内の記述によって読み込み先が決まるということでした。ここではもう少し詳しくこれらの記述について説明しておきます。

 まず「インスタンス化の際の()内」に記述されているのは、メソッドの場合と同様「引数」です。上記の場合、引数として「new クラス名()」が記述されている点は、キーボード入力・テキストファイル入力ともに共通しています。このような形式の記述は、まず最初に「new クラス名()」として書かれているクラスのインスタンス化を行い、その結果できあがったインスタンスを直接「BufferedReader」のインスタンス化のための引数として渡す、という意味を持っています。つまり、キーボード入力ならばまず最初に「InputStreamReader」のインスタンス化を、テキストファイル入力ならば最初に「FileReader」のインスタンス化を、それぞれ実行して、その結果を引数として「BufferedReader」のインスタンスが生成されるわけです。

 これらはそれぞれ、以下の命令の短縮形だったのです。

キーボード入力の場合:
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader reader = new BufferedReader(isr);

テキストファイル入力の場合:
FileReader fr = new FileReader("file name");
BufferedReader reader = new BufferedReader(fr);

 入力先がキーボードなのかテキストファイルなのかの違いは、「InputStreamReader」と「FileReader」の違いとして考えることができるのです。「InputStreamReader」はインスタンス化の際に引数として「System.in」という特殊なデータを取ります。これはJavaにおいて「標準入力(すなわち、キーボード入力)」を表すデータです。この「InputStreamReader」のインスタンスが、文字列型データの入力を可能にします。それに対して「FileReader」はインスタンス化の引数として文字列型で「ファイル名」を要求します。この「FileReader」のインスタンスは、ここで渡されたファイル名を持つファイルからの文字列型データの入力を可能にします。

 その後のデータ読み込みの手順はキーボード入力の場合もテキストファイル入力の場合も全く同様です。すなわち「BufferedReader」をインスタンス化し、「readLineメソッド」によって文字列型のデータとして「時限」「科目名」「教室名」をそれぞれ1行ずつ読み込んで「ClassTable」の属性に代入してゆけばよいのです。

(3)ClassTableWriterの拡張

 以上の知識を総合して、「ClassTableWriter」の拡張を行います。今回は細かい手順についてのヒントを出さずに、拡張のポイントだけをまとめておきます。それを参考にトライしてみて下さい。

拡張のポイント

その1:拡張の内容
 従来の「ClassTableWirter」を、キーボードではなくテキストファイルから入力されるデータを元にデータファイルを出力するプログラムとなるように拡張します。また、その際に扱うデータを<1日分の時間割>から<時間割>に変更します。
その2:拡張実現のための方針1・テキストファイル入力の実現
 従来の「ClassTableWriter」のデータ入力を担当した「readData」メソッドを、テキストファイル入力を行うように書き換えます。その際、引数として「ファイル名」を取るようにします。
その3:拡張実現のための方針2・<1日分の時間割>から<時間割>への変更
 「ClassTableWriter」の属性を、<1日分の時間割>から<時間割>へと変更します。そして「readData」メソッドにおいて<1日分の時間割>を作成していた部分を、
<時間割>を作成するように変更します。さらに、「fileOut」メソッドにおけるファイル出力の対象を、<1日分の時間割>から<時間割>へと変更します。その際に、出力されるファイルのファイル名はあらかじめ(例えば「Week.data」等に)決めておきましょう。データファイルには共通の名前を付けておいた方が、読み込みの際にいちいちファイル名を入力する必要がなく便利だからです。
その4:その他の変更
 これらの変更に伴い、メイン・メソッドの記述も一部変更を行います。具体的には、読み込む「テキストファイルのファイル名」(「readData」メソッドに引数として渡す)をユーザーから聞き出せるようにする、ということです。

>>解答例のプログラム


リンク:

<全体のトップページ>

     |

<第7講のトップページ>

     |-------------------------|

<第7講・その1>        <第7講・その2