第3章.ファイルを用いたデータ入出力 - sapporo gakuin...
TRANSCRIPT
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
35
第第33章章..フファァイイルルをを用用いいたたデデーータタ入入出出力力
【学習のねらい】
① データをファイルへ出力する(書き込む)方法を学習する。
② データをファイルから入力する(読み込む)方法を学習する。
大量のデータを処理する場合は、ファイルからデータを読み込んでから処理を行います。
また、プログラムが終了すると変数に記憶されたデータは消えてしまうので、処理結果を
残すためにはファイルに保管しておくことが必要になります。このようにファイルを用い
たデータ入出力はコンピュータを使った処理の場合必須の技術です。そこで本章では、Java
言語を用いたファイルによるデータ入出力の仕方を学習しましょう。
3-1 ファイルへの出力1-ファイルへの書き込み方
まず、簡単な例でデータをファイルに書き込む方法を学びましょう。次のようなフレーム
を作成してください(作成の際、プロジェクト名は Kiso3_1 として下さい)。
そしてボタンクリック時のプログラムを次のように記述してください。
<プログラム>
private void jButtonWriteActionPerformed(ActionEvent evt) {
String Data=jTextFieldData.getText();
try { ⑥
// ファイル Test1.txtを出力ストリーム fwとして定義する
FileWriter fw= new FileWriter("Test1.txt"); ①
// fwへの出力時にバッファリング機能をつける。
BufferedWriter bw= new BufferedWriter(fw); ②
// さらに出力時に便利なメソッドを使用可能にする。
PrintWriter fout = new PrintWriter(bw); ③
fout.print("出力データ:"+Data); //ファイルへの書き込み ④
jLabelMessage.setText("書き込み終了しました。");
fout.close(); //ファイルを閉じる ⑤
}
catch(Exception em) { ⑥
jLabelMessage.setText("エラー発生:"+em);
}
}
jButtonWrite
jTextFieldData
jLabelMessage
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
36
加えてプログラム(NewJFrame.java)の先頭行に以下の波線部を加えて下さい。以下、フ
ァイルへの入出力を行う場合、これは必ず(毎回)必要になります。
import java.awt.event.ActionEvent;
・・・
import javax.swing.SwingUtilities;
import java.io.*;
見慣れない命令が目につきますが、それらの説明の前にまずは実行して動作を確認して
みましょう。このプログラムは、入力文字列欄に入力した文字列を「Test1.txt」というフ
ァイルに出力する(書き込む)プログラムです。確認のため、プログラムを起動させ入力
文字列欄に「これはテスト出力です。」と入力し、[書き込み]ボタンをクリックして下さ
い。
すると、「待機中」というメッセージが「書き込み終了しました。」というメッセージに
変わります。このとき、プログラム(プロジェクト)と同じフォルダ内(今の場合「Kiso3_1」
内)に「Test1.txt」というファイルができています。そこで、メモ帳や秀丸エディタなど
の適当なテキストエディタで開き、次のように出力されていることを確認してください。
<プログラムの解説>
0.ストリームについて
Java 言語では入出力データをストリームという概念で表します。ストリームとは流れと
いう意味です。”流れ”と言われても最初はピンと来ないかもしれませんが、大量のデータ
をファイルに書き込むあるいは読み出す様は、まさにデータが流れて行くように見えるた
めストリームと呼ばれているようです。Java 言語では、ファイルへのデータ入出力はスト
リームの制御(ストリームの行き着く先はどこか?→出力ファイルの指定、ストリームは
どこから来るのか→入力ファイルの指定、ストリームをどのように区切って入出力する
か?等々)を行うことによって実現されます。Java 言語では、ストリームを制御するため
に各種のクラスを用意しています。以下、ファイルへの出力に用いられる FileWriter、
BufferedWriter そして PrintWriter というクラスの用い方を上の例を用いて解説しましょ
う。①、②などの番号は、p.35 のプログラム中に付した番号に対応しています。
出力データ:これはテスト出力です。 <Test1.txt>
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
37
① 出力ファイルの定義-FileWriter クラス
FileWriter fw= new FileWriter("Test1.txt");
によって、FileWriterクラスのオブジェクトを fwという名前で生成しています。一般に、
あるクラスのオブジェクトを生成するためには、
クラス名 オブジェクト名 = new クラスのコンストラクタ
と記述します。クラスの定義やオブジェクトの生成については、「プログラミング」テキ
ストの第7章で学習しました。忘れてしまった人はテキストを読み返して下さい。さて、
FileWriter クラスの場合、右辺のコンストラクタ FileWriter()のカッコ内に引数とし
て出力ファイル名を指定します。この文によって、ここで扱うストリーム fw が、ファイ
ル「Test1.txt」に流れ着く出力ストリームとして定義されるのです。
② 出力ストリームをバッファリング可能にする-BufferedWriter クラス
ファイルへデータの出力を行う場合、データ(ストリーム)を1単位(通常はバイト単
位)毎に転送すると、ハードディスクなどファイル媒体側の受け入れ準備ができるまで待
ち時間が発生し効率が悪くなります。そこで、一旦、出力データをメモリにため込み(書
き込み)、ファイル側の書き込み準備ができた段階で順次データを書き込む処理が行われ
ます。この処理をバッファリングと言います。
BufferedWriter bw= new BufferedWriter(fw);
によって、bw はバッファリング機能付きのストリームとなります。
③ サービス機能を付加する-PrintWriter クラス
ファイルへのデータ出力を行う場合、PrintWriter クラスに用意されている print()
あるいは println()メソッドを用いるのが普通です。*)そのため、次の文によって出力
ストリームを PrintWriter クラスの提供するサービス機能つきのストリームにしました。
PrintWriter fout = new PrintWriter(bw);
なお、上では説明のために3つに分解して記述したのですが、通常は出力ストリームの定
義は次のように1行で(一度に)記述されます。
PrintWriter fout = new PrintWriter(new BufferedWriter(new
FileWriter("Test1.txt")));
本講義でも以下ではこのように1行で記述することにします。
*)少し補足すると、FileWriter クラスにもデータを書き込む write()というメソッド
が用意されているのですが、実数値を出力できない、またデータの改行を指定できな
いなど、実用上不便な点が多かったので、PrintWriter クラスが開発され、その中の
print()および println()メソッドが使われるようになったのです。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
38
④ ファイルのクローズ
ファイル処理を終了したら、close()メソッドにより、必ずファイルを閉じなければな
りません。
⑤ エラー処理-try~catch 文
FileWriter fw= new FileWriter("Test1.txt");
などのように、出力ストリームを定義する際、何らかの理由で指定したファイルを出力フ
ァイルとして確保できなかった場合、(FileWriter クラスは)IOException という例外情
報を発行します。Exception(例外)とは、想定通りに行かなかった場合、つまりエラー
が発生した状態を指すプログラミング用語です。Java 言語では、Exception 情報を発行
する事を、”Exception 情報を投げる”と言います。そして投げられた Exception 情報を
キャッチ(catch)して(エラーに対応した)適切な処理を行うよう、文法的に義務づけ
ています。一般に、ファイルの入出力を行う場合、
try {
ファイル入出力の処理
}
catch (Exception em){
エラーに対応した処理
}
という形で処理を記述します。今の場合、エラー処理は
catch(Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
となっており、これは、エラー情報を(ラベルに)表示させる処理を行うという意味です。
catch 文の()内の引数 em には Exception の情報、つまりエラーメッセージが書き込まれ
ているのです。
少し説明が長くなりましたので、実際に色々な動作を確認することで理解を深めましょ
う。上のプログラムに以下の波線部を追加して実行してみて下さい。
void jButtonWrite_actionPerformed(ActionEvent e) {
String Data=jTextFieldData.getText();
try {
・・・
fout.print("出力データ:"+Data); //ファイルへの書き込み
fout.print(”次の出力");
jLabelMessage.setText("書き込み終了しました。");
・・・
以下同じ
}
ファイル入出力の場合
の定型の書き方
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
39
先程と同様に文字列入力欄に「次の出力」と入力してボタンをクリックすると、ファイル
「Test1.txt」の内容は次のようになっているはずです。
つまり、print()メソッドを連ねると、該当文字列が(横に)続けて出力されます。
それでは、
というように、改行して出力するにはどうしたらよいでしょうか? そのためには、最初の
print()メソッドを println()メソッドに変更すればよいのです。次のように書き換えて
実行してみて下さい。今度は、上のように改行して出力されるはずです。
fout.println("出力データ:"+Data); //ファイルへの書き込み
fout.print(”次の出力");
このように println()文は()内の文字列を出力後改行する、という意味を持ちます。
【基礎課題 3-1】
上の例では、文字列を採り上げましたが、整数でも同様に出力できます。
上のプログラムに波線部の修正および点線枠の追加を行って実行して下さい。
・・・
fout.println("出力データ:"+Data); //ファイルへの書き込み
fout.println("次の出力");
int a=2,b=5;
fout.println("a="+a+" b="+b);
fout.println("a+b="+(a+b));
jLabelMessage.setText("書き込み終了しました。");
・・・
そして、「Test1.txt」にどのように出力されるかを確認し、枠内を埋めて下さい。
<Test1.txt の出力結果>
出力データ:これはテスト出力です。次の出力
<Test1.txt> 出力データ:これはテスト出力です。
次の出力
出力データ:これはテスト出力です。
次の出力
a=2 b=5
a+b=7
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
40
<解説>
文字列同士を「+」で結ぶと、それは連結を意味する、ということはこれまで学習した通
りです。しかし、上のプログラムでは整数型と文字列型を「+」記号で結んでいます。「そ
んなことが許されるのか?」と首をかしげた人もいることと思いますが、Java 言語ではこ
のような書き方を認めています。そして結果を確かめてみれば分かるとおり、整数と文字
列が連結されて表示されます。例えば次のようなプログラムを考えた場合、
int a=2;
String Ans="a="+a;
文字列型変数 Ans の値は「a=2」となります。このように、文字列と整数を+記号で結ぶ
と、整数が自動的に文字列化され、文字列の連結として処理されます。これは非常に便利
なので、Java 言語では頻繁に利用されます。
もちろん、実数についても同様です。例えば
int a=2;
String Ans="a/4="+(a/4.0);
というプログラムを実行すると、文字列型変数 Ans の値は「a/4=0.5」となります。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
41
3-2 ファイルへの出力2-ダイアログによるファイル名の指定
3-1節では、出力ファイル名が固定されているものとして、プログラム中で直接ファ
イル名を指定していました。しかし、実際には、プログラム実行時にファイル名を指定で
きた方が便利です。次の課題でその方法を学習しましょう。
【基礎課題 3-2】
前節と同様、次のようなフレームを作成してください。
次に、ファイル名を指定することができる「JFileChooser」というコンポーネントを使
用します。その使い方は次の通りです。指示にしたがって設定して下さい。
<JFileChooser の使用方法>
まず、コンポーネントパレットの「More Components」タブにある「JFileChooser」コ
ンポーネントを選択(クリック)して下さい。
続いて、Eclipse ワークベンチの右側にある「アウト
ライン」ビューの「inst –NewJFrame・・・」をクリック
して下さい。
すると、次ページの「コンポーネント名」指定画面が
現れるので、ここでは、「jFileChooser1」のまま、[OK]
ボタンをクリックします。
jButtonWrite
jTextFieldData
jLabelMessage
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
42
すると、JFileChooser の表示内容であるファイル名指定画面がフレーム上に表示されま
す。
表示をフレームに戻すために、「アウトライン」ビュー
の「this – JFrame・・・」(フレームを意味します)をクリ
ックします。すると、フレームが表示されるようになりま
す。これで、JFileChooser コンポーネントが使用可能に
なりました。
次ページへ進んで下さい。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
43
以下の課題では、幾つかのファイルをデータ入出力に用います。そこで、それらファイ
ルを一括して管理できるよう、適当な場所にファイル保管用のフォルダ
「IOFile」を作成しておいて下さい。フォルダ名は何でも良いのですが、
以下では、ファイル保管用フォルダ名が「IOFile」という名前であるとし
て説明しています。
そしてボタンクリック時のプログラムを次ページのように作成します。
private void jButtonWriteActionPerformed(ActionEvent evt) {
String Data=jTextFieldData.getText();
try {
// ダイアログボックスを開く
jFileChooser1.showSaveDialog(this); ①
// 出力ファイル名を指定する
File FName=jFileChooser1.getSelectedFile(); ②
// 出力ストリームを定義する
PrintWriter fout=new PrintWriter(new BufferedWriter
(new FileWriter(FName))); ③
fout.println("出力データ:"+Data); //ファイルへの書き込み
jLabelMessage.setText("書き込み終了しました。");
fout.close(); //ファイルを閉じる
}
catch(Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
}
なお、プログラムの先頭に、
import java.io.*;
を追加することを忘れないようにして下さい。ファイル名を指定している①~③以外は前
節のプログラムと同じです。その説明は後回しにして、とりあえずプログラムを実行して
みましょう。
実行後、前節同様次のような起動画面が現れます。
ここで次ページのように、入力文字列欄に「これはテスト出力です。」と入力し[書き込
み]ボタンをクリックすると・・・
p.36 で説明した通り、プログラムの先頭です。メソッド
内の先頭ではありませんので注意して下さい。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
44
次のように出力ファイル指定のためのダイアログボックスが現れます。ここで、次のよう
に、先程作成した「IOFile」フォルダを指定します。
さらに、ファイル名として「output.txt」を入力し、[保存]ボタンをクリックすると・・・
ダイアログボックスは消え、元の画面に戻ります。
この時点で、出力ファイル「output.txt」に入力文字列欄に指定した文字列が書き込まれて
います。確認のため、[IOFile]フォルダ内の「output.txt」ファイルの中身を適当なエデ
ィタでチェックしてみて下さい。次のように書き込まれているはずです。
このように、JFileChooser コンポーネントを用いると、プログラム実行時に任意のファ
出力データ:これはテスト出力です。 <output.txt>
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
45
イルを指定することができます。それでは、次ページで先程のプログラムの①~③の意味
を確認しておきましょう。
<プログラムの解説>
① showSaveDialog()メソッドにより、保存先のファイルを指定するダイアログボック
スが表示されます。()内は通常 this を指定するものと理解しておいて下さい。
② getSelectedFile()メソッドは、ファイルダイアログボックスで指定したファイル
名を返します。ファイル名は「File」クラス(型と考えて結構です)の変数(オブジ
ェクト)に代入できます。ここでは、その変数名を「FName」としています。
③ 下線部に示したように、今まで"output.txt"等と直接ファイル名を指定していた部
分をファイル名の変数 FNameに置き換えています。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
46
3-3 ファイルからの入力1-ファイルからの読み込み方
さて、本章の後半では、ファイルからのデータ入力の方法を学習することにします。
例として【基礎課題 3-2】で作成した出力ファイル「output.txt」を読み込んでその内容
を表示させるプログラムを考えましょう。
【基礎課題 3-3】
次のようなフレームを作成してください。
【基礎課題 3-2】と同様に入力ファイルを実行時にファイルダイアログボックスで指定する
ので、p.41 で説明した通り JFileChooser コンポーネントを設定して下さい。そして、ボタ
ンクリック時のプログラムを次のように記述します。
private void jButtonReadActionPerformed(ActionEvent evt) {
String Data;
try {
jFileChooser1.showOpenDialog(this);
File FName=jFileChooser1.getSelectedFile();
BufferedReader fin=new BufferedReader ②
(new FileReader(FName));
Data=fin.readLine(); //ファイルからの読み込み ③
jTextFieldData.setText(Data); //読み込んだデータの表示
fin.close();
jLabelMessage.setText("読み込み終了しました。");
}
catch (Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
}
※ プログラムの冒頭に、「import java.io.*;」を追加することを忘れないように注意
して下さい(p.36 参照)。
<プログラムの解説>
① ダイアログボックスで指定した(入力)ファイル名を受け取る部分は出力ファイルの
場合と同じです。ただし、入力先のファイルを指定するダイアログボックスを開く際に
は、showOpenDialog()メソッドを用います。
jButtonRead
jTextFieldData
jLabelMessage
①
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
47
② 入力ストリーム「fin」の指定(定義)です。出力ストリームの場合と比べて PrintWriter
クラスに該当する部分がありませんが、それ以外は出力ストリームの場合と同様です。
③ readLine()メソッドは、入力ストリーム(今の場合ファイル「FName」)から1行分
だけ読み込み、その値を文字列として返します。
プログラムの内容はほぼ理解できると思いますので早速実行して動作を確認してみまし
ょう。
このプログラムを用いればどの様なファイルでも、その内容を表示させることができ
ます。ただし、最初の1行分だけですが・・・。
このプログラムを起動し、[ファイル
からの入力と表示]ボタンをクリッ
クします。
すると、ファイル指定のためのダ
イアログボックスが現れるので、
ここで、【基礎課題 3-2】で作成し
た「output.txt」を指定します。
ファイル名の指定後、[開く]ボタ
ンをクリックすると・・
元の画面に戻り、ファイル
「output.txt」の内容が表示されま
す。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
48
【基礎課題 3-4】- 複数行のデータの読み込み
今度は、複数行のデータをファイルから読み込んでみましょう。入力
ファイルとして、科目の HP の該当部分に掲載している「input.txt」フ
ァイルをダウンロードし、前節で作成したフォルダ「IOFile」にコピー
して下さい。このファイルには、次のように、あるテストの5人分の得
点がデータとして入力されています。今、このファイルからデータを読
み込み、このテストの平均点を表示するプログラムを考えましょう。
作成するプログラムの動作内容は次の通りです。
55
60
92
38
71
<input.txt>
プログラムを起動すると左のよ
うな画面が現れます。
ここで、[データの読み込み]ボタ
ンをクリックすると・・・
入力ファイルを指定するダイアロ
グボックスが開くので、ここで、
今ダウンロードしたファイル
「input.txt」を指定します。その
後[開く]ボタンをクリックする
と・・・
元の画面に戻り、表示が「読み込
み終了しました。」に変わります。
この時点で入力データの読み込み
は完了しています。
続いて[平均点]ボタンをクリック
すると、テストの平均点が表示され
ます。
jButtonRead
jButtonAvg
jTextFieldAvg
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
49
それではプログラムを作成しましょう。今の場合、簡単のためにデータの個数は5つであ
ることが分かっていることにしましょう。作成に当たってポイントとなるのは次の点です。
① 5つのデータ(得点)を保管するために、大きさが5の配列型変数を用意する。
② ファイルから1行ずつデータを読み込む方法は【基礎課題 3-3】で分かっているので、
5つのデータを読み込むには、それを5回繰り返せば良い。
③ 今の場合、読み込んだデータ(得点)を保管する配列型変数は、ボタン[データの読
み込み]とボタン[平均点]の2つのイベントハンドラ(メソッド)で共有(参照)す
るので、配列型変数の宣言は、メソッドの外で行わなければならない。なぜならメソッ
ドの中で宣言すると、そのメソッド内でしか参照できないからである。→「プログラミ
ング」テキスト「6-12 ローカル変数とインスタンス変数」参照。
以上を念頭に置いてプログラムを記述すると次のようになります。
int[] Tokuten=new int[5]; //得点を保管する配列(整数型)
int Num; //データの個数
private void jButtonReadActionPerformed(ActionEvent evt) {
String Data;
try {
jFileChooser1.showOpenDialog(this);
File FName=jFileChooser1.getSelectedFile();
BufferedReader fin=new BufferedReader
(new FileReader(FName));
// ファイルからの読み込み
Num=5; //データ個数の設定
for (int i=0;i<Num;i++) {
Data=fin.readLine();
Tokuten[i]=Integer.parseInt(Data);
}
jLabelMessage.setText("読み込み終了しました。");
fin.close();
}
catch (Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
}
private void jButtonAvgActionPerformed(ActionEvent evt) {
// 平均点の計算
int sum=0;
for (int i=0;i<Num;i++) {
sum=sum+Tokuten[i];
}
double Avg= sum/(double)(Num); ③
jTextFieldAvg.setText(String.valueOf(Avg));
}
①
②
得点の合計の計算
[データの読み込み]ボタン
[平均点]ボタン
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
50
<プログラムの解説>
① 5つのデータを保管する整数型配列変数 Tokuten とデータの個数を保管する整数型変
数 Num を宣言します。場所は、メソッド(イベントハンドラ)の外側ならどこでも良
いのですが、ここでは、分かりやすく[データの読み込み]ボタンクリック時のイベン
トハンドラの上に置きました。
② データの個数分だけ(1行ずつ)データを読み込み、それを Tokuten[i]に順次代入
しています。データを読み込んだ段階では文字列型なので、Tokuten[i]に代入する際
には整数型への変換が必要であることに注意して下さい。
③ ここで平均点を計算しています。Java 言語のルールにより、「整数/整数」は小数点以
下が切り捨てられ整数になる、という点に注意して下さい。そのため、分母の Num を
実数型に型キャスト(変換)しています。型キャストについては「プログラミング」テ
キスト p.86(2012 年度版:p.84)を参照して下さい。
プログラム作成後は実行して動作を確認して下さい。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
51
3-4 ファイルからの入力2-連続したデータ読み込み
【基礎課題 3-4】では予め入力データの個数が分かっているものとしていましたが、実際
にはデータの個数が分からない状態で入力処理を行う場合が少なくありません。そこで次
の課題で、ファイル中のデータの個数が予め分かっていない場合に対応できるように(【基
礎課題 3-4】のプログラムを)改良しましょう。
【基礎課題 3-5】
【基礎課題 3-4】のプログラムにおいて、配列の大きさを下線部のように修正し、データ
読み込み部分を枠線部のように修正して下さい。それ以外は以前の通りです。
int[] Tokuten=new int[100]; //得点を保管する配列 ①
int Num; //データの個数
private void jButtonReadActionPerformed(ActionEvent evt) {
String Data;
try {
jFileChooser1.showOpenDialog(this);
File FName=jFileChooser1.getSelectedFile();
BufferedReader fin=new BufferedReader
(new FileReader(FName));
// ファイルからの読み込み
int i=0;
while ((Data=fin.readLine())!=null) {
Tokuten[i]=Integer.parseInt(Data);
i++;
}
Num=i; //データの個数の保管
jLabelMessage.setText("読み込み終了しました。");
fin.close();
}
catch (Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
}
<プログラムの解説>
① 予めデータの個数が決まっていないので、予想される最大個数程度を配列の大きさに
指定しておきます。ここでは 100 にしています。
② readLine()メソッドによって、ファイル中の最終データの次を読み込んだ場合、そ
こには何もないので、「null」という特別の値になります。null は「空っぽ」という意
味です。「while ((Data=fin.readLine())!=null)」では、入力ストリームから
②
[データの読み込み]ボタン
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
52
読み込んだ値を Data に代入し、その値が「null」ではない場合、つまりデータが存在
する限り読み込み続ける、という条件指定になっています。なお、while ループ内の処
理を行う回数は「データの個数」に等しいので、カウンタ i がそのままデータの個数に
なっています。
上のように修正後、プログラムを実行し、前節同様きちんと動作することを確認して下
さい。
【基礎課題 3-6】
【基礎課題 3-5】のプログラムに、以下のように最高点を求め表示するボタンを加えて下
さい。
下の枠内を埋めて最高点を求めるプログラムを完成させて下さい。
private void jButtonMaxActionPerformed(ActionEvent evt) {
int MAX=Tokuten[0];
for(int i=1; i<Num;i++) {
}
jTextFieldMax.setText(String.valueOf(MAX));
}
ヒント
最高点を求める処理は、「2-3 配列の応用-最大・最小を求める」の【基礎課題 2-4】(p.23)
と同じです。
入力ファイルを指定してデー
タを読み込んだ後、[最高点]
ボタンをクリックすると、最
高点が表示される。
jTextFieldMax
jButtonMax
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
53
【応用課題 3-A】
【基礎課題 3-6】に今度は、(下のように)最低点を求める処理を加えて下さい。
【応用課題 3-B】
HP の該当部分より、あるテストの得点の入ったファイル「score.txt」
をダウンロードして下さい。そして、【応用課題 3-A】のプログラムを用い
て、このテスト得点のデータの平均点および、最高点、最低点を求めて下
さい。
※ このデータは 100 名以上です。配列の大きさを 150 に変更して下さい。
55
90
85
38
80
・・・
70
62
67
75
<score.txt>
次に、左のように、[デー
タの読み込み]ボタンをク
リックした時に受験者人
数を表示するように拡張
して下さい。
加えた部分
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
54
【応用課題 3-C】
さらに【応用課題 3-B】を拡張しましょう。今、テストの得点が 50 点以上であれば合格
であるとしましょう。そこで、「score.txt」から得点を読み込んで、[合格者]ボタンをクリ
ックすると、合格者数を表示する部分を加えて下さい。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
55
3-5 1行に複数のデータがある場合のデータ読み込み
3-4 節で、ファイルからデータを読み込む際の一般的な方法を学習しました。しかし、そ
こでは、1行に一つのデータが書き込まれていることが想定されていました。ところが実
際の場面では、ファイルの1行に複数のデータが書き込まれている場合が少なくありませ
ん。その際は、個々のデータを区切って読み込む事が必要になります。本節では、このよ
うにファイルの1行に複数のデータが存在する場合の読み込み方を学習します。
【基礎課題 3-7】
HP の該当部分から、ファイル「score2.txt」をダウンロード
して下さい。このファイルには右のように、あるテストの結果
が、氏名と得点という形で保管されています。そして、氏名と
得点はカンマ記号「,」で区切られています。
そこで、このファイルから、氏名と得点を(別々に)読み込
み、その氏名だけを表示するプログラムを作成しましょう。(基
本的な部分は【基礎課題 3-5】のプログラムと同様です。異なる
のは、「氏名」と「得点」という2つのデータを読み込むという
点のみです。)
なお、ダウンロードしたファイル「score2.txt」はこれまで同
様、フォルダ「IOFile」に保存されているものとします。
作成するプログラムの動作結果は以下の通りです。
花形 満 ,55
轟 次郎 ,63
金田正太郎,39
鮎原こずえ,87
浅丘ユミ ,48
矢吹 丈 ,70
東 八郎 ,35
星 明子 ,77
諸星 団 ,59
伊達直人 ,44
<score2.txt>
jButtonRead
jTextArea1
jButtonDisplay
jLabelMessage
プログラムを起動すると、次
の画面が現れます。
ここで、[データ読み込み]
ボタンをクリックする
と・・・
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
56
なお、フレームの設計に当たっては、3-2 節で学習した通り、JFileChooser コンポーネン
トを設定しておく事を忘れないようにして下さい(pp.41~42 参照)。
それでは、プログラムの作成に取りかかりましょう。まず、プログラムの冒頭部に以下
の2行(波線部)を追加して下さい。
import java.awt.event.ActionEvent;
・・・
import javax.swing.SwingUtilities;
import java.io.*;
import java.util.*;
「java.io.*」が必要なのはこれまで通りですが、「java.util.*」が必要なのは、こ
の中に、複数のデータを区切って読み込む機能を有するクラスが入っている(そしてここ
でそれを利用する)からです。
[データ読み込み]ボタンのイベントハンドラ、および、氏名と得点を保管する配列、
そしてデータの個数を保管する変数の宣言は次の通りです。
入力ファイルを指定するためのダ
イアログボックスが現れます。
ここで、ダウンロードしたファイ
ル「score2.txt」を指定し、[開く]
ボタンをクリックします。
すると、データの読み込みが
完了し「読み込み終了しまし
た。」というメッセージが表示
されます。
続いて[表示]ボタンをク
リックすると、テキストエリ
アに、読み込んだ受験者の全
員の氏名が表示されます。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
57
String[] Name=new String[100]; //氏名を保管する配列
int[] Tokuten=new int[100]; //得点を保管する配列
int Num; //データの個数
private void jButtonReadActionPerformed(ActionEvent evt) {
String Data;
try {
jFileChooser1.showOpenDialog(this);
File FName=jFileChooser1.getSelectedFile();
BufferedReader fin=new BufferedReader
(new FileReader(FName));
int i=0;
while ((Data=fin.readLine())!=null) {
StringTokenizer tk=new StringTokenizer(Data,","); ①
Name[i]=tk.nextToken();
Tokuten[i]=Integer.parseInt(tk.nextToken());
i++;
}
Num=i;
jLabelMessage.setText("読み込み終了しました。");
fin.close();
}
catch (Exception em) {
jLabelMessage.setText("エラー発生:"+em);
}
}
枠線部以外は、基本的に【基礎課題 3-5】と同様なので説明は省きます。ここでは、新し
く出てきた「StringTokenizer」クラスについて説明すれば十分でしょう。
<StringTokenizer クラスについて>
① StringTokenizer tk=new StringTokenizer(Data,",");
によって、StringTokenizer クラスのオブジェクト(変数と考えて結構です)を「tk」と
いう名前で生成しています。
一般に、「new StringTokenizer(文字列,区切り記号)」という形で生成したオブジェ
クトには、「文字列」の中身が「区切り記号」で分解され、各々が順に(文字列として)
保管されます。上の例で具体的に説明しましょう。ファイルの最初の1行が変数 Dataに
読み込まれとき、Dataの中身は次のようになっています。
変数 Dataの中身
花形 満 ,55
そして、「StringTokenizer tk=new StringTokenizer(Data,",");」によって、
Dataの中身は区切り記号「,」によって分解され、tkの中身は次のようになります。
②
[データの読み込み]ボタン
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
58
1番目のトークン 2番目のトークン
tk 花形 満 55
区切られた個々の文字列を「トークン」と呼びます。
② StringTokenizerクラスには、「nextToken()」メソッドがあり、これにより tk に
保管されているトークンを順に取り出すことができます。今の場合、最初の
nextToken()メソッドで「氏名」が取り出され、2番目の nextToken()メソッドで得
点が取り出される訳です。
以上のように、StringTokenizer クラスを利用することにより、任意の区切り記号で
区切られたデータを順次取り出すことができます。
次に、[表示]ボタンのイベントハンドラは次の通りです。
private void jButtonDisplayActionPerformed(ActionEvent evt) {
String Data="";
for (int i=0;i<Num;i++) {
Data=Data+Name[i]+"\n"; }
jTextArea1.setText(Data);
}
氏名を(1行に1名ずつ)順に表示させるので、「Name[i]+改行記号」を連結させた結
果を、jTextArea1 に表示させています。
プログラムを作成したら実行し、動作を確認して下さい。
[表示]ボタン
キーボード上では半角の「¥」です。使用
フォントによっては¥と表示されます。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
59
3-6 ファイル入出力の応用
【応用課題 3-D】
【基礎課題 3-7】を修正して、次のように、最高点をとった人の氏名とその得点を表示さ
せるプログラムを作成して下さい。
<ヒント>
最高点を求める部分は【基礎課題 3-6】と同様です。そこでは、”勝ち抜き戦”方式で変
数 MAX に最高点候補が順次代入されて行きました。最高点候補者の氏名についても、同様
のこと(最高点候補を MAX に代入する時に、その人の氏名を、最高点候補者氏名に対応す
る文字列型変数、例えば MaxName に代入する)を行えばよいのです。
プログラムを起動すると次の画面
が現れます。
ここで、[データの読み込み]ボタ
ンをクリックすると・・・
入力ファイル指定のダイアログ
ボックスが現れるので、ここで、
「score2.txt」を指定します。
ここまでの動作は【基礎課題
3-7】と同じです。
データ読み込み完了
後、[最高点]ボタンを
クリックすると、最高
点と、それをとった人
の氏名が表示されま
す。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
60
【応用課題 3-E】
【応用課題 2-B】では、3択のアンケートの集計を行うプログラムを考
えました。その際回答データはテキストエリアに直接書き込んだのです
が、その回答データをファイルから読み込むようにしましょう。HP の該
当部分からファイル「Ank.txt」をダウンロードして下さい。このファイ
ルには 150 名分の回答結果が書き込まれています。
作成するプログラムの動作は次の通りです。
3
2
2
2
・・・
<Ank.txt>
プログラムを起動すると、次のよう
な画面が現れます。
ここで、[データ読み込み]ボタンを
クリックすると・・
入力ファイルを指定するための
ダイアログボックスが現れるの
で、ここで、ファイル「Ank.txt」
を指定します。
データの読み込み完了後、[集計]ボ
タンをクリックすると、選択肢1~
3それぞれの回答に対する度数が集
計され表示されます。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
61
【応用課題 3-F】
次のような、クイック保存機能のある簡易メモ帳を作って下さい。
プログラムを起動すると次
の画面が現れます。
起動後、「メモ帳」欄に適
当にメモを記入します。
ここで、作業を中断しなけ
ればならなくなったとし
ます。そこで、[メモを保
存]ボタンをクリックし、
今のメモの内容を保存し
ておきます。
そしてプログラムを終
了させます。
データ構造とアルゴリズム論 平成 30 年 5 月 2・5 月 9 日
62
<ヒント>
① [メモを保存]ボタンをクリックしたときに、適当なファイル(プログラム中で指定)
に、jTextArea コンポーネントの内容を保管する(書き込む)ようにします。
② [保存したメモを呼び出す]ボタンをクリックしたときに、上で書き込んだファイル
から1行ずつ読み込みます。要領は【基礎課題 3-5】と同じです。そして、読み込んだ
内容を、jTextArea コンポーネントに表示させれば良いのです。要領は【基礎課題 3-7】
の[表示]ボタンのイベントハンドラと同様です。
<補足>
jTextArea コンポーネントはそのままでは、行端で自動的に折り返してくれません。つま
り意図的に改行しない限り次行へ移りません。これでは不便なので、自動的に行端で折り
返すようにするためには次のようにします。
右の様に jTextAreaコンポーネントの lineWrap
プロパティ(Basic ではなく Expert 欄内にありま
す)を true に変更します(最初は false になって
います)。これにより、自動折り返しが有効になり
ます。
再び、プログラムを起動
し、作業を再開します。起
動後、[保存したメモを呼
び出す]ボタンをクリック
します。すると、先程保存
したメモの内容が表示さ
れます。