第10章 ファイル入出力

10.2 ファイルの仕組みを知る

キーボードからデータを入力したり、画面に出力を行う仕組みは大変便利です。しかしデータを長く保存する場合や、大量に読み込む場合にはファイルを使ってデータを管理することは欠かせません。
ファイルを利用してデータの読み書きを行うJavaコードもストリームを使うことによって、これまで入出力とほぼ同じような仕組みで作成できるようになっています。
ファイルを読み込むことを「ファイル入力」、ファイルへ書き込むことを「ファイル出力」と言います。
本テキストではファイル入出力を行う為に、以下のクラスを利用した方法を紹介します。

  • ファイル入力:Scannerクラス
  • ファイル出力:PrintWriterクラス

では次項よりファイルの入出力操作を学習していきましょう。

10.2.1 ファイルからデータを読み込み一部の内容を表示するプログラム

テキストファイルを読み込み、その内容の一部を画面に表示します。Eclipseを使ったテキストファイルの作成方法、および、ファイル入力の方法について学習しましょう。

読み込みファイルの準備

ファイル入力処理に利用するSample.txtファイルをEclipseの機能を利用して作成します。

① ファイルの作成

myproj_basicプロジェクト右クリック > 新規 > ファイルを選択


図 10.1.1: Javaの入出力を支えるストリーム

② 新規ファイルコンソール

ファイル名(M):のテキストボックスに「Sample.txt」と入力 > 完了ボタンを押す


図 10.2.2: ファイル作成準備2

③ ファイル作成の確認

myproj _basicプロジェクト直下に「Sample.txt」ファイルが作成され、そのファイルが開くことを確認する。


図 10.2.3: ファイル作成準備3

④ ファイル内容の記述

以下に示す内容を「Sample.txt」ファイル内に記述して保存して下さい。


図 10.2.4: ファイル作成準備4

これでファイル入力処理に利用するファイル作成準備は完了です

Eclipse機能を利用してのファイル作成

Eclipseの機能を利用してテキストファイル(.txt)を作成しましたが、その他の形式(.csv、.html等)のファイルを作成したい場合もこの機能を利用して「ファイル名.拡張子」で拡張子を作成したい形式に変更すれば作成することができます

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: ReadFileShowData
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.File;
  import java.io.FileNotFoundException;
  import java.util.Scanner;

  public class ReadFileShowData {
    public static void main(String[] args) {
      try{
        //Scannerクラスのオブジェクト生成
        Scanner sin = new Scanner(new File("Sample.txt"));

        String strLine1 = sin.nextLine(); //1行読み出し
        String strLine2 = sin.nextLine(); //1行読み出し

        System.out.println(strLine1);
        System.out.println(strLine2);

        //ストリームのクローズ
        sin.close();

      }catch(FileNotFoundException e){
        System.out.println("入力ファイルが見つかりません。");
      }
    }
  }
  
実行結果

解説

3~5行目でファイル入力処理に必要なクラスのインポートを行っています。
3行目は読み込みファイルに関する情報を扱うクラス、4行目はファイルが見つからなかった場合の例外クラス、5行目はこれまでキーボード入力で利用したScannerクラスをインポートしています。
   3:import java.io.File;
   4:import java.io.FileNotFoundException;
   5:import java.util.Scanner;

11行目でScannerクラスのオブジェクト生成を行っています。これまでのキーボード入力と違い、引数にFileクラスのオブジェクトを渡している点です。Fileクラスオブジェクト生成時の引数が読み込みたいファイルのパス(場所)になります。ファイル名のみを指定した場合、プロジェクト直下が参照先になります。    11:Scanner sin = new Scanner(new File("Sample.txt"));
 

11行目の処理を行うことでScannerクラス型変数のsinが、ファイル実体の場所情報を指し示すようになります。


図 10.2.5: ファイル取り込み

13行目でScannerクラスのインスタンスメソッドである「nextLine()」メソッドを利用して、取り込んだファイルデータの1行目のデータを取得し変数strLine1に代入しています。    13:String strLine1 = sin.nextLine(); //1行読み出し
 

nextLine()メソッドは1行目のデータ(■世界の挨拶「こんにちは」)を取得(※①)して、次の読み出し位置を次の先頭行に設定(※②)します。そして戻り値として取得したデータ(■世界の挨拶「こんにちは」)を返します。(※③)


図 10.2.6: 読み込みデータの読み出し1回目

ポイント
  • 読み込んだファイルから1行文字列データを取得する場合、nextLineメソッドを利用する。
  • nextLineメソッドを1回使用すると、読み出し位置は次の文字列(次の行)の先頭になる。

続いて14行目も「nextLine()」メソッドを利用して、取り込んだファイルデータの2行目を取得し変数strLine2に代入しています。      14:String strLine2 = sin.nextLine(); //1行読み出し

nextLine()メソッドは2行目のデータ(日本語はこんにちは)を取得(※①)して、読み出し位置を次の先頭行に設定(※②)します。そして戻り値として取得したデータ(日本語はこんにちは)を返します。(※③)


図 10.2.7: 読み込みデータの読み出し2回目

16、17行目は13、14行目で読み出した文字列を画面に出力しています。      16:System.out.println(strLine1);
   17:System.out.println(strLine2);
 

実行結果からも分かるように、ファイルの1行目と2行目のデータが正しく表示されています。

20行目ではファイルの読み出しが終わったので、使用していたストリームを閉じます。読み出しが終わったら必ずクローズを行います。    20:sin.close();
 

今回のプログラムでは例外処理が組み込まれている点に注目して下さい。
11行目でScannerクラスを使ってファイル入力処理を行うと、チェック例外である「FileNotFoundException」が送出されてしまいます。ここで思い出して欲しいのですが、チェック例外は必ず処理(try-catch)を行わないとコンパイルエラーになることです。ファイル入力を行う場合は、例外処理を忘れないようにして下さい。
   11: try{
   12: //Scannerクラスのオブジェクト生成
   13: Scanner sin = new Scanner(new File("Sample.txt"));
   14: ・・・
   15: }catch(FileNotFoundException e){
   16: System.out.println("入力ファイルが見つかりません。");
   17: }
 

続いて繰り返し処理を利用して、読み込んだファイルデータ全てを表示するプログラムを紹介します。

10.2.2 ファイルからデータを読み込み全ての内容を表示するプログラム

前項のプログラムでは1行ずつファイル読み込み処理を行っていましたが、このプログラムでは繰り返し処理を利用してファイル内容全てを画面に表示します。ファイル内の全てのデータを読み取る為のロジックについて学習しましょう。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: ReadFileShowAllData
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.File;
  import java.io.FileNotFoundException;
  import java.util.Scanner;

  public class ReadFileShowAllData {
    public static void main(String[] args) {
      try{
        //Scannerクラスのオブジェクト生成
        Scanner sin =  new Scanner(new File("Sample.txt"));

        //繰り返し処理で全データを読み出し
        while(sin.hasNextLine()){
          String strLine = sin.nextLine();
          System.out.println(strLine);
        }
        //ストリームのクローズ
        sin.close();

      }catch(FileNotFoundException e){
        System.out.println("入力ファイルが見つかりません。");
      }
    }
  }
  
実行結果

解説

11行目でScannerクラスを利用して「Sample.txt」ファイルの読み込み処理を行っています。    11: Scanner sin = new Scanner(new File("Sample.txt"));
 

14~17行目で繰り返し処理である「while」とScannerクラスの「hasNextLine()」メソッドを利用して、読み込んだ全データのチェックを行いつつ読み出し処理を行っています。    14: while(sin.hasNextLine()){
   15: String strLine = sin.nextLine();
   16: System.out.println(strLine);
   17: }

 

ここで重要なのは「hasNextLine()」メソッドです。このメソッドの役割は読み込んだデータの現在の読み出し行をチェックし、データがあれば「true」無ければ「false」を返してくれます。これを「while」と組み合わせることで読み出せるデータがあれば内部の処理(データ1行読み出して、画面に表示する)を行い、無ければ繰り返し処理が終わる仕組みになります。そうすることで全てのデータを読み出すことが可能になります。


図 10.2.7: 繰り返し処理を利用して全データの読み出し

19行目で使用したストリームのクローズ処理を行っています。    19: sin.close();

ポイント
  • 繰り返し処理「while」とScannerクラスの「hasNextLine()」メソッドを利用すれば、読み込んだファイルデータの全データを読み出すことが簡単に行える。

10.2.3 テキストファイルへデータを書き出すプログラム

テキストファイルへ文字列を書き出す処理を行います。ファイル出力の方法、および、作成されたファイルのEclipse上での確認方法について学習しましょう。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: WriteFileData
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.BufferedWriter;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;

  public class WriteFileData {
    public static void main(String[] args) {
      try{
        //書き込みファイルのオープン
        PrintWriter pw = new PrintWriter
          (new BufferedWriter(new FileWriter("output1.txt")));
        pw.println("■世界の「ありがとう」");
        pw.println("日本語ではありがとう");

        //書き込みファイルのクローズ
        pw.close();
        System.out.println("ファイルに書き込みが終了しました。");

      }catch (IOException e) {
        System.out.println(e+"入出力エラーです。");
      }
    }
  }
  
実行結果

書き込みファイルoutput1.txtの確認

①プログラム実行後の状態
※プログラムを実行しただけでは書き込みファイル「output1.txt」はEclipse上には表示されません。


図 10.2.8: 書き込みファイルの確認1

②書き込みファイルの表示
プロジェクト名を右クリック > リフレッシュ(F)をクリックする。


図 10.2.9: 書き込みファイルの確認2

③書き込みファイルの表示確認
プロジェクトのリフレッシュ(更新)を行うことでファイルがEclipse上に表示されます。


図 10.2.10: 書き込みファイルの確認3

④書き込みファイルの内容を確認
output1.txtファイルをダブルクリックし、ファイルが開いたら書き込みデータの内容を確認します。


図 10.2.11: 書き込みファイルの確認4

解説

3~6行目でファイル出力処理に必要なクラスのインポートを行っています。
3行目はバッファを介して書き込むクラス、4行目は書き込みファイルを扱うクラス、5行目はファイル入出力関連を扱う例外クラス、6行目は書き出し処理を行うクラス等の4つのクラスを利用します。
3、4、6行のクラスは全て文字ストリームを使用しています。
   3: import java.io.BufferedWriter;
   4: import java.io.FileWriter;
   5: import java.io.IOException;
   6: import java.io.PrintWriter;
 

12、13行目でPrintWriterクラスをBufferedWriterクラスのオブジェクトとFileWriterクラスのオブジェクトを引数に、書き込みファイル「output1.txt」をオープンしています。入力処理と同じようにファイル名にパスの指定が無い場合、プロジェクト直下に書き込みファイルが作成されます。    12: PrintWriter pw = new PrintWriter
   13: (new BufferedWriter(new FileWriter("output1.txt")));
 

14、15行目はPrintWriterクラスの「println()」メソッドを利用して、文字列を1行改行つきで書き込んでいます。改行無しの書き込みを行いたい場合は「print()」メソッドが用意されています。    14: pw.println("■世界の「ありがとう」");
   15: pw.println("日本語ではありがとう");
 

18行目で書き込みファイルをクローズしています。ファイル書き込み処理ではこのクローズ処理が大変重要になっていて、この処理を行わないと書き込みファイルへのデータの書き込みが正しく行われません。ファイル出力処理を行う場合、必ずこのクローズ処理を忘れないように注意して下さい。    18: pw.close();
 

10~23行目では例外処理を行っています。13行目のFileWriterクラスを利用するとチェック例外である「IOException」が送出されている為です。ファイル出力を行う場合は、例外処理を忘れないようにして下さい。    10: try{
   11: //書き込みファイルのオープン
   12: PrintWriter pw = new PrintWriter
   13: (new BufferedWriter(new FileWriter("output1.txt")));
      ・・・
   21: }catch (IOException e) {
   22: System.out.println(e+"入出力エラーです。");
   23: }
 

ポイント
  • ファイル出力処理を行うにはPrintWriter、BufferedWriter、FileWriterの3つのクラスを使って行う。書き込みファイルを生成するには、必ずクローズ処理を行う。

10.2.4 テキストファイルへ繰り返し処理を利用し配列データを書き出すプログラム

テキストファイルへ繰り返し処理を利用して、配列データの文字列を書き出す処理を行います。繰り返し処理と配列を利用した効率の良いファイル出力のロジックについて学習しましょう。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: WriteFileManyData
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.BufferedWriter;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintWriter;

  public class WriteFileManyData {
    public static void main(String[] args) {
      //書き込み用データを配列に用意
      String[] strArray = {"■世界の「ありがとう」",
          "日本語はありがとう",
          "韓国語はカムサハムニダ",
          "英語はサンキュー",
          "中国語はシェシェ",
          "ネパール語はダンニャバード",
          "ドイツ語はダンケ シェーン",
          "スペイン語はグラシアス",
          "フランス語はメルスィーボクー",
          "タイ語はコー(プ)クンマーグ",
          "ベトナム語はカム オンアウム",
          "ハワイ語はマハロ"};
      try{
        //書き込みファイルのオープン
        PrintWriter pw = new PrintWriter
          (new BufferedWriter(new FileWriter("output2.txt")));

        //繰り返し処理で書き込みを行う
        for(int i=0;i<strArray.length;i++){
          pw.println(strArray[i]);
        }

        //書き込みファイルのクローズ
        pw.close();
        System.out.println("ファイルに書き込みが終了");

      }catch (IOException e) {
        System.out.println(e+"入出力エラーです。");
      }
    }
  }
  
実行結果

書き込みファイルoutput2.txtの確認

前項の確認手順を実施し、書き込みファイル「output2.txt」を開き内容を確認します。


図 10.2.12: output2.txtの確認

解説

11~22行目で書き込み用データを文字列配列に用意しています。    11: String[] strArray = {"■世界の「ありがとう」",
   12: "日本語はありがとう",
   13: "韓国語はカムサハムニダ",
   14: "英語はサンキュー",
   15: "中国語はシェシェ",
   16: "ネパール語はダンニャバード",
   17: "ドイツ語はダンケ シェーン",
   18: "スペイン語はグラシァス",
   19: "フランス語はメルスィーボクー",
   20: "タイ語はコー(プ)クンマーグ",
   21: "ベトナム語はカム オンアウム",
   22: "ハワイ語はマハロ"};
 

25、26行目では前項で学習した方法で、ファイル名「output2.txt」の書き込みファイルをオープンしています。    25: PrintWriter pw = new PrintWriter
   26: (new BufferedWriter(new FileWriter("output2.txt")));
 

29~31行目で配列データ数分だけ繰り返し処理を行い、ファイルへ書き込み処理を行っています。    29: for(int i=0;i<strArray.length;i++){
   30: pw.println(strArray[i]);
   31: }
 

34行目で書き込みファイルのクローズを行っています。    34: pw.close();
 

繰り返し処理を利用して配列データを書き込む手法はそれほど難しくなかったはずです。
これまで繰り返し処理と連携して配列データを、全て画面に表示することは行ってきました。今回のプログラムではデータの出力先が画面から書き込みファイルになっているだけの違いでしかありません。

クローズ処理

書き込み処理でクローズ処理を忘れてしまうとファイルの生成は行いますが、書き込んだデータが保存されないので必ず処理を行わないといけません。ですが読み込み処理でクローズ処理を怠っても書き込み処理のように、メインプログラムの動作に影響を及ぼすものではありません。
読み込み処理でクローズ処理を行わないと、読み込んだ情報はメモリ領域に暫く残ったままになってしまいます。Javaの機能(ガベージコレクション)でメモリ開放はいずれ行われますが、その処理が間に合わないほどメモリ領域を使用してしまうと徐々にリソース(メモリ)が枯渇し、最悪プログラムの強制終了などの要因になってしまいます。リソースを利用するものはメインプログラムに影響がなくても、必ずクローズ処理を行うようにしましょう。

では次にこれまでの項で学習してきた、ファイル入力と出力両方を利用したプログラムを紹介します。

10.2.5 読み込みファイルデータを元に統計情報をファイルに書き出すプログラム

点数データファイルを読み込み、統計情報結果をテキストファイルに書き出す処理を行います。ファイル入出力を行うプログラムについて学習しましょう。

読み込みファイルの準備

Eclipse機能のファイルを作成する方法で、以下の内容のcsvファイルをプロジェクト直下に作成して下さい。
※csv:Comma Separated Value(カンマ・セパレーテッド・バリュー)の略で、一般的には「,(カンマ)」で区切られたデータファイルを指します。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: FileInOutData1
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.*;
  import java.util.*;

  public class FileInOutData1 {
    public static void main(String[] args) {
      int sum = 0; // 合計点格納用変数
      double ave = 0.0; // 平均点格納用変数
      String[] strData = null; // 読み込みデータの分割格納用配列

      ArrayList<String> subjectList = new ArrayList<String>(); // 教科格納用配列
      ArrayList<Integer> scoreList = new ArrayList<Integer>(); // 点数格納用配列

      try {
        // 教科データファイルの読み込み
        Scanner sin = new Scanner(new File("subject_data.csv"));

        // 全データを配列に読み込む
        while (sin.hasNextLine()) {
          // 読み込み1行データカンマで分割
          strData = sin.nextLine().split(",");

          // 各配列にデータを格納
          subjectList.add(strData[0]);
          scoreList.add(Integer.parseInt(strData[1]));
        }
        // ストリームのクローズ
        sin.close();
        System.out.println("ファイルの読み込みが終了しました。");

        // 書き込みファイルのオープン
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
          "statistics.txt")));

        // 読み込みデータをファイルに書き込む
        for (int i = 0; i < subjectList.size(); i++) {
          pw.println(subjectList.get(i) + "<--->" + scoreList.get(i));
        }

        // 合計点を算出しファイルに書き込む
        for (int i = 0; i < scoreList.size(); i++) {
          sum += scoreList.get(i);
        }
        pw.println("合計点:" + sum);

        // 平均点を算出しファイルに書き込む
        ave = (double) sum / scoreList.size();
        pw.println("平均点:" + ave);

        // 書き込みファイルのクローズ
        pw.close();
        System.out.println("ファイルへ書き込みが終了しました。");

      } catch (FileNotFoundException e) {
        System.out.println("入力ファイルが見つかりません。");
      } catch (IOException e) {
        System.out.println(e + "入出力エラーです。");
      }
    }
  }
  
実行結果

書き込みファイルstatistics.txtの確認

10.2.3項の確認手順を実施し、書き込みファイル「statistics.txt」を開き内容を確認します。


図 10.2.13: statistics.txtの確認

解説

このプログラムはこれまで学習してきた内容を複数応用したものになっています。以下のキーワードを念頭において解説を読んで下さい。
①ファイル入力処理
②ファイル出力処理
③文字列の分割処理(StringクラスのSplitメソッド)
④可変長配列の利用(ArrayListクラス)
⑤繰り返し処理と配列の連携
⑥文字列を整数型に変換(Integerクラス)
⑦明示的なキャスト

3、4行目でこのプログラムに必要なクラスをインポートしています。パッケージに*を利用するとその配下のクラスを全て利用できることを思い出してください。    3: import java.io.*;
   4: import java.util.*;

8~10行目では各変数を宣言と同時に初期化しています。    8: int sum = 0; //合計点格納用変数
   9: double ave = 0.0; //平均点格納用変数
   10: String[] strData = null; //読み込みデータの分割格納用配列

12、13行目では文字列と整数型を扱う可変長配列であるArrayListクラスをオブジェクト化しています。    12: ArrayList subjectList = new ArrayList(); //教科格納用配列
   13: ArrayList scoreList = new ArrayList(); //点数格納用配列

17行目ではファイル名「subject_data.csv」を指定して、ファイル入力処理を行っています。    17: Scanner sin = new Scanner(new File("subject_data.csv"));

20~27行目では繰り返し処理を利用して、読み込んだデータ全て読み出しています。
22行目では読み出した1行データを「,(カンマ)」で分割する為、StringクラスのSplitメソッドを利用して配列変数のstrDataに格納しています。
25行目では22行目で分割されたデータ0番目の、「教科名」をsubjectListに格納しています。
26行目では22行目で分割されたデータ1番目の、「点数」を整数型に変換してscoreListに格納しています。strData配列は文字列型の為、変換しないと型が違う為格納できない点に注意して下さい。
   20: while(sin.hasNextLine()){
   21: //読み込み1行データカンマで分割
   22: strData = sin.nextLine().split(",");
   23:
   24: //各配列にデータを格納
   25: subjectList.add(strData[0]);
   26: scoreList.add(Integer.parseInt(strData[1]));
   27: }

29行目では読み込み処理で利用したストリームのクローズ処理を行い、30行目で読み込みが終了したメッセージを画面に表示しています。    29: sin.close();
   30: System.out.println("ファイルの読み込みが終了しました。");

33、34行目ではファイル名「statistics.txt」で、書き込みファイルのオープン処理を行っています。    33: PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
   34: "statistics.txt")));

37~39行目では繰り返し処理とArrayList(subjectList)の格納データ数を利用して、配列に格納している読み込みデータ全ての書き込み処理を行っています。    37: for(int i=0;i<subjectList.size();i++){
   38: pw.println(subjectList.get(i) + "<--->" + scoreList.get(i));
   39: }

42~44行目も繰り返し処理とArrayList(scoreList)の格納データ数を利用して、配列に格納した全データの合計点を算出しています。
45行目では上記の処理で算出した、合計点の書き込み処理を行っています。
   42: for(int i=0;i<scoreList.size();i++){
   43: sum += scoreList.get(i);
   44: }
   45: pw.println("合計点:" + sum);

48行目では合計点が格納された変数sumをdouble型にキャストし、ArrayList(scoreList)の格納データ数で除算して平均点を算出しています。
49行目では上記の処理で算出した、平均点の書き込み処理を行っています。
   48: ave = (double)sum / scoreList.size();
   49: pw.println("平均点:" + ave);

52行目ではこれまで書き込んだデータでファイルを生成する為のファイルのクローズ処理を行い、53行目で書き込みが終了したメッセージを画面に表示しています。    52: pw.close();
   53: System.out.println("ファイルへ書き込みが終了しました。");

ファイルの出力結果から確認できるように、読み込みデータ、合計点、平均点が正しく書き込まれているのが確認できます。

10.2.6 提供クラスライブラリを利用してファイル入出力処理を行うプログラム

Javaが用意している標準のクラスライブラリではなく、既に用意されているユーザー定義クラス(FileIn.java、FileOut.java)を利用してファイルの入出力処理を行います。

ファイル構成
① FileIn.java: ファイル入力関連の制御を行うクラス
② FileOut.java: ファイル出力関連の制御を行うクラス
③ FileInOutData2.java: 前項のFileInOutData1.javaの入出力に関連する処理部分を、提供クラスライ ブラリ(FileIn.java、FileOut.java)を利用した処理に置き換えています。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: FileIn
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.File;
  import java.io.FileNotFoundException;
  import java.util.Scanner;

  // テキストファイルから入力されたデータを読み取ります。
  public class FileIn {
    private Scanner sin = null; // Scannerクラス

    // ファイルのオープンを行うメソッド
    public boolean open(String fname) {
      boolean sts = true;
      try {
        // 読み込みファイルオープンに相当する処理
        sin = new Scanner(new File(fname));
      } catch (FileNotFoundException e) {
        System.out.println("ファイル名に誤りがあります\n" + e);
        sts = false;
      }
      return sts;
    }

    // 読み込んだファイルデータからの1行読み出し処理を行うメソッド
    public String readLine() {
      String buff;

      // 読み込み可能データがあるか判定
      if (sin.hasNextLine()) {
        buff = sin.nextLine();
      } else {
        buff = null;
      }
      return buff;
    }

    // ストリームのクローズを行うメソッド
    public boolean close() {
      boolean sts = true;
      try {
        sin.close(); // ストリームのクローズ
      } catch (Exception e) {
        System.out.println("ストリームクローズエラー\n" + e);
        sts = false;
      }
      return sts;
    }
  }
  

FileIn.java 解説

クラス名
FileIn

メンバ構成
①フィールド変数: Scanner sin(Scannerクラスのオブジェクトを扱う変数)
②ファイルの読み込み処理を行うメソッド

メソッド名: open
引数: String fname(読み込みファイルの場所情報)
戻り値: true(ファイルの読み込み成功)/false(ファイルの読み込み失敗)
概要: 引数で受け取った情報からScannerクラスを利用してファイルの読み込み処理を行い、そのオブジェクト情報をフィールド変数に格納します。読み込み成功の場合はtrueを、失敗の場合はfalseを戻り値として返します。

③ファイルデータから1行分のデータを読み出すメソッド

メソッド名: readLine
引数: なし
戻り値: 読み出し1行データ/null(データが無い場合)
概要: 読み込みデータをチェックして、読み出せるデータがあれば1行データを読み出し、無ければnullを戻り値として返します。

④ストリームのクローズ処理を行うメソッド

メソッド名: close
引数: なし
戻り値: true(ストリームのクローズ成功)/false(ストリームのクローズ失敗)
概要: openメソッドで利用したストリームのクローズ処理を行います。クローズ成功の場合はtrueを、失敗の場合はfalseを戻り値として返します。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: FileOut
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.io.*;

  // 指定されたデータをテキストファイルへ書き込みます。
  public class FileOut {
    private BufferedWriter bw = null; // BufferedWriterクラス

    // ファイルのオープンを行うメソッド
    public boolean open(String fname) {
      boolean sts = true;
      try {
        // 書き込みファイルオープンに相当する処理
        bw = new BufferedWriter(new FileWriter(fname));
      } catch (IOException e) {
        System.out.println("ファイル名に誤りがあります\n" + e);
        sts = false;
      }
      return sts;
    }

    // ファイルへのデータ書き込みを行うメソッド
    public boolean writeln(String str) {
      boolean sts = true;
      try {
        bw.write(str); // 1行分のデータをファイル出力
        bw.newLine(); // 行区切り文字を出力
      } catch (IOException e) {
        System.out.println("書き込みエラー\n" + e);
        sts = false;
      }
      return sts;
    }

    // ファイルのクローズを行うメソッド
    public boolean close(){
      boolean sts = true;
      try {
        bw.close(); // ファイルのクローズ
      } catch (IOException e) {
        System.out.println("ファイルクローズエラー\n" + e);
        sts = false;
      }
      return sts;
    }
  }
  

FileOut.java解説

クラス名
FileOut

クラス概要
ファイル出力関連の制御処理を行う

メンバ構成
①フィールド変数:BufferedWriter bw(BufferedWriterクラスのオブジェクトを扱う変数)
②書き込みファイルのオープン処理を行うメソッド

②ファイルの読み込み処理を行うメソッド

メソッド名: open
引数: String fname(書き込みファイルの場所情報)
戻り値: true(ファイルオープン成功)/false(ファイルオープン失敗)
概要: 引数で受け取った情報からBufferedWriterクラスを利用して書き込みファイルのオープン処理を行い、そのオブジェクト情報をフィールド変数に格納します。オープン成功の場合はtrueを、失敗の場合はfalseを戻り値として返します。

③書き込みファイルへ1行分のデータを書き込むメソッド

メソッド名: writeln
引数: String str:書き込み文字列データ
戻り値: true(書き込み成功)/false(書き込み失敗)
概要: 引数で受け取った文字列をオープンしたファイルに書き込みます。書き込み成功の場合はtrueを、失敗の場合はfalseを戻り値として返します。

④書き込みファイルのクローズ処理を行うメソッド

メソッド名: close
引数: なし
戻り値: true(ファイルクローズ成功)/false(ファイルクローズ失敗)
概要: openメソッドでオープンした書き込みファイルのクローズ処理を行います。クローズ成功の場合はtrueを、失敗の場合はfalseを戻り値として返します。

① ソース・フォルダー: myproj_basic/src
② パッケージ: jp.co.f1.basic.ch10
③ 名前: FileInOutData2
④ 作成するメソッド・スタブの選択:public static void main(String[] args) にチェックを入れる

  package jp.co.f1.basic.ch10;

  import java.util.ArrayList;

  public class FileInOutData2 {
    public static void main(String[] args) {
      int sum = 0; // 合計点格納用変数
      double ave = 0.0; // 平均点格納用変数
      String[] strData = null; // 読み込みデータの分割格納用配列
      String strLine = null; // 1行データ格納用変数

      ArrayList<String> subjectList = new ArrayList<String>(); // 教科格納用配列
      ArrayList<Integer> scoreList = new ArrayList<Integer>(); // 点数格納用配列

      // 提供クラスのオブジェクト化
      FileIn in = new FileIn(); // ファイル入力
      FileOut out = new FileOut(); // ファイル出力

      // 教科データファイルの読み込み
      if (in.open("subject_data.csv") == false) {
        System.exit(1);
      }

      // 全データを配列に読み込む
      while ((strLine = in.readLine()) != null) {
        // 読み込み1行データカンマで分割
        strData = strLine.split(",");

        // 各配列にデータを格納
        subjectList.add(strData[0]);
        scoreList.add(Integer.parseInt(strData[1]));
      }
      // ストリームのクローズ
      if (in.close() == false) {
        System.exit(2);
      }
      System.out.println("ファイルの読み込みが終了しました。");

      // 書き込みファイルのオープン
      if (out.open("statistics.txt") == false) {
        System.exit(3);
      }

      // 読み込みデータをファイルに書き込む
      for (int i = 0; i < subjectList.size(); i++) {
        out.writeln(subjectList.get(i) + "<--->" + scoreList.get(i));
      }

      // 合計点を算出しファイルに書き込む
      for (int i = 0; i < scoreList.size(); i++) {
        sum += scoreList.get(i);
      }
      out.writeln("合計点:" + sum);

      // 平均点を算出しファイルに書き込む
      ave = (double) sum / scoreList.size();
      out.writeln("平均点:" + ave);

      // 書き込みファイルのクローズ
      if (out.close() == false) {
        System.exit(4);
      }
      System.out.println("ファイルへ書き込みが終了しました。");

    }
  }
  
実行結果

書き込みファイルstatistics.txtの確認

前項のプログラムと同じ結果になることを、statistics.txtの書き込み内容を確認して下さい。

解説

基本部分は前項のFileInOutData1.javaと同じため、提供クラスを利用している箇所について解説を行っていきます。
10行目で読み込んだファイルから読み出した、1行データ格納用変数を定義しnullで初期化しています。
   10: String strLine = null; //1行データ格納用変数

16、17行目で今回提供されているファイル入出力関連を扱うクラスのオブジェクト生成を行っています。    16: FileIn in = new FileIn(); //ファイル入力
   17: FileOut out = new FileOut(); //ファイル出力

20~22行目でFileInクラスの「open()」メソッドに、読み込みファイルの場所情報を引数に設定しファイルの読み込み処理を行っています。その際if文で判定処理を行い、openメソッドの戻り値がfalse(読み込み失敗)の場合、System.exitメソッドを利用してプログラムの強制終了を行うようにしています。    20: if(in.open("subject_data.csv") == false){
   21: System.exit(1);
   22: }

25行目でFileInクラスの「readLine()」メソッドを利用して1行分のデータを取得しています。その読み出したデータを変数strLineに受け取り、その値がnullでなければ繰り返す処理になっています。その結果読み込んだデータを全て読み出せる処理になっています。27行目は変数strLineに格納されている1行分のデータを「,(カンマ)」で分割しています。    25: while((strLine = in.readLine()) != null){
   26: //読み込み1行データカンマで分割
   27: strData = strLine.split(",");
     ・・・
   32: }

34~36行目でFileInクラスの「close()」メソッドを利用してストリームのクローズ処理を行っています。その際if文で判定処理を行い、closeメソッドの戻り値がfalse(クローズ失敗)の場合、System.exitメソッドを利用してプログラムの強制終了を行うようにしています。    34: if(in.close() == false){
   35: System.exit(2);
   36: }

40~42行目でFileOutクラスの「open()」メソッドに、書き込みファイルの場所情報を引数に設定し書き込みファイルのオープンを行っています。その際if文で判定処理を行い、openメソッドの戻り値がfalse(読み込み失敗)の場合、System.exitメソッドを利用してプログラムの強制終了を行うようにしています。    40: if(out.open("statistics.txt") == false){
   41: System.exit(3);
   42: }

46、53、57行目ではFileOutクラスの「writeln()」メソッドを利用して、引数に設定した文字列をファイルに書き込処理を行っています。    46: out.writeln(subjectList.get(i) + "<--->" + scoreList.get(i));
   53: out.writeln("合計点:" + sum);
   57: out.writeln("平均点:" + ave);

60~62行目でFileOutクラスの「close()」メソッドを利用して書き込みファイルのクローズ処理を行っています。その際if文で判定処理を行い、closeメソッドの戻り値がfalse(クローズ失敗)の場合、System.exitメソッドを利用してプログラムの強制終了を行うようにしています。    60: if(out.close() == false){
   61: System.exit(4);
   62: }

今回のプログラムでは、例外処理についての記述が無くなっている事に気づかれたでしょうか?FileInOutData2.javaで今回利用したFileInとFileOutクラス内の各メソッドがチェック例外の処理を行ってくれている為、mainメソッドで行わなくてもよくなっています。その代わり各メソッド内で例外の発生状況に応じて戻り値にtrue(成功)とfalse(失敗)が設定されています。mainメソッドで例外処理を行う必要はなくなりましたが、メソッドの戻り値に対しての判定処理が必要になっています。

まとめ

今回のプログラムでは提供されるクラス「FileIn.java」、「FileOut.java」を利用してファイルの入出力処理を行いました。
標準のクラスライブラリと何が違うかと言うと初めから提供されているものなのか、ユーザーが自作したものなのかの違いだけです。使い方も同様で、もしも別パッケージに含まれているのならインポート処理を行い、同一パッケージならそのまま利用することができます。今回は同一パッケージに含めていますので後者になります。後はプログラム内で提供クラスのオブジェクト生成を行い、処理に合わせて各メソッド(機能)を利用します。
Javaプログラミングを行っていると標準クラスライブラリ以外にも、今回のようなユーザー定義のクラスライブラリを利用することが多くなります。その際にメインプログラム側でどのように利用すれば処理を実現できるか、提供されるクラス機能の仕組みを把握することが重要になってきます。

ファイルパスの指定方法

本章では入力ファイルと出力ファイルをプロジェクト直下のみで扱ってきました。それ以外の場所も当然指定することができます。その例をいくつか紹介しておきます。

例)プロジェクト直下のfileフォルダーで入出力を行う場合

Scanner sin = new Scanner(new File(“file/ファイル名”)); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(“file/ファイル名”)));

例)Cドライブのdataフォルダーで入出力を行う場合

Scanner sin = new Scanner(new File(“c:\\data\\ファイル名”)); PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(“c:\\data\\ファイル名”)));

前者の例を相対パス指定、後者の例を絶対パス指定と呼び、「\\」と「/」は同じ意味になりどちらを指定しても問題ありません。

NEXT>> 10.3 本章のまとめ