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