Java 入門

ホーム > 基本的な I/O > テキストファイルの読み込みと書き込み

テキストファイルの読み込みと書き込み

ここではテキストファイルから文字を読み込む方法をいろいろとみていきましょう。

また読み込んだデータは、標準の出力へ書き出します。

ここでの例で hello.txt というファイルには Hello! という文字が書いてあります。

まずは単純な FileInputStream によるデータの読み込み

C言語などでは FILE* fp ... fp = fopen( ... fprintf(fp, ... なんて書いたことがある(とか学校で習った)人もいるかとおもいますが、 Java では FILE* などは使いません。

Java ではいろいろな方法がありますがここでは、ファイルを開き、そこからデータを汲み取るための基本は FileInputStream である、として順番に見ていきましょう。

package com.keicode.java.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class StreamTest0 {

  public static void main(String[] args) {
    
    try {

      FileInputStream fileInputStream = 
        new FileInputStream("/home/keisukeo/tmp/hello.txt");
      
      int i;
      while( (i = fileInputStream.read()) != -1){
        if(0x1f<i && i<0x7e){
          System.out.println((char)i);
        }
      }

      fileInputStream.close();
      
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    
  }

}

"/home/keisukeo/tmp/hello.txt" というテキストファイルから文字を読み込んで表示しようとしています。

FileInputStream のコンストラクタにファイルのパスを渡すだけで OK です。

この入力ストリームの read メソッドで 1 バイト毎にデータを読み込んで、それを表示してみましょう。read メソッドが返す値は int 型です。 これだけでは「文字」と言えませんね。これを char にキャストしたところで、ASCII コードでは何の文字にあたる、という風に意味付けして始めて文字データといえます。

ちなみに、入力元にはどんなデータが入っているか分からないものとして、念のため 0x1f から 0x7f までの範囲の値の場合のみ出力しています。

結果は次のとおり。

FileInputStream による読み込み

確かに H, e, l, l, o, ! という文字が表示されました。

InputStreamReader で少し変換

上でみたように、FileInputStream でも read メソッドを持っていてバイト列を読み込むことができます。 これを文字の列として読み込むための橋渡しをするのが、 InputStreamReader です。

名前がややこしいので一応言っておくと、最初のが「インプットストリーム」系だったのですが、 今回出てきたのは「ストリームリーダー」です。

ストリームそのもの(およびそれの派生クラス)と、リーダー・ライターというのが出てきますので注意してください。

イメージ的には「なんとかストリーム」というのがファイルとかバイト列そのもので、read とかデータへのアクセス用のメソッドがありますが、 原始的なものしか通常ありません。リーダー・ライターというので、それらへの読み込み、書き込み用の便利な機能を追加する感じです。

さて、InputStreamReader に戻ります。

InputStreamReader のコンストラクタに FileInputStream を渡して次のようにします。

package com.keicode.java.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class StreamTest1 {

  public static void main(String[] args) {
    
    try {

      int size;
      char[] cbuf = new char[2];
      
      InputStreamReader inReader = 
        new InputStreamReader(
          new FileInputStream("/home/keisukeo/tmp/hello.txt"));
            
      while( (size = inReader.read(cbuf)) != -1){
        
        System.out.print(cbuf);
        System.out.println( "(" + size + ")" );

        for(int i=0;i<cbuf.length;i++){
          cbuf[i]=0;
        }
        
      }
            
      inReader.close();
      
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    
  }

}

こうして、もとの FileInputStream から文字ベースでデータを取り出す手段が手に入りました。

ちなみに、ここでは最大 2 文字ずつ数回に分けて読み出しているので、結果は次のようになります。

InputStreamReader による読み込み

念のためいうと、小さいバッファでこうして繰り返し読むのは通常あまり望ましいことではないです。 基本的な考えは、下のレイヤーに現実的な大きめのサイズのバッファを渡してアプリケーション側での処理を少なくする方が良い場合が多いです。

StringWriter による String のバッファリング

前の例ではチョット読んで、チョット書き出して、、、とやりましたが、そうしないで読み込んだものを溜め込んで(バッファリング)しておいて、 全部読み込み終わってから出力してみましょう。

文字を溜め込むのは、StringWriter で実現できます。(この場合は StringBuilder や StringBuffer でも良いのですがここではあえて java.io.Writer の StringWriter を使っています)

package com.keicode.java.test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;

public class StreamTest1b {

  public static void main(String[] args) {
    
    try {

      int size;
      char[] cbuf = new char[2];
      
      InputStreamReader inReader = 
        new InputStreamReader(
          new FileInputStream("/home/keisukeo/tmp/hello.txt"));
      StringWriter sWriter = new StringWriter();
      
      while( (size = inReader.read(cbuf)) != -1){
        sWriter.write(cbuf, 0, size);
      }
      
      System.out.println(sWriter.toString());
      
      inReader.close();
      
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
    
  }

}

全部読み込んでから出力、ということで今度はちゃんと "Hello!" とつながって表示されました。

InputStreamReader による読み込み

FileReader

「ファイルを開いてそこから読み込む」という基本的な操作のために、FileReader というリーダーも用意されています。

こちらは上でやったみたいに FileInputStream を作ってそれを InputStreamReader に渡すということをやらなくとも、 FileReader にパスを渡すとその中でストリームをオープンして、読込みを可能な状態にしてくれます。

package com.keicode.java.test;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class StreamTest2 {

  public static void main(String[] args) {

    try {

      char[] cbuf = new char[1];
      
      FileReader fileReader = 
        new FileReader("/home/keisukeo/tmp/hello.txt");
      
      while( (fileReader.read(cbuf)) != -1){
        System.out.print("[");
        System.out.print(cbuf);
        System.out.println("]");
      }
      
      fileReader.close();

    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }

  }

}

ためしに 1 文字ずつ読み込むと次のようになりました。

FileReader による読み込み

BufferedReader で一行毎に読込み

いよいよ次はテキストファイルを一行毎に読むという、よくやりそうなことをやります。

一行毎に読むということは、ある程度データを読んで溜め込んでおき、改行文字 (CR, LF) などを見つけて、そこまでを取り出す、という作業になりますよね。 ですから「一行ずつ読む」ということをするのは、BufferedReader (バッファーされたリーダー、ということで) です。

BufferedReader の readLine メソッドは改行文字までの一行を返します。

package com.keicode.java.test;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class StreamTest3 {
  public static void main(String[] args) {
    try {
  
      BufferedReader buffReader = 
        new BufferedReader(
          new FileReader("/home/keisukeo/tmp/hello.txt"));
      
      String s;
      
      while( (s = buffReader.readLine()) != null ){
        System.out.println(s);
      }

      buffReader.close();
      
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

この実行結果は次のとおり。

BufferedReader による読み込み

これはとても簡単ですね。

ホーム > 基本的な I/O > テキストファイルの読み込みと書き込み