文字ストリーム

入出力の基本知識で説明したjava.io.FileReader及びjava.io.FileWriterを利用してテキストファイルの入出力について説明します。

ビジネスシステムでは、テキストファイルを操作する場面は色々な局面で利用されます。

文字ファイルの入出力サンプル

文字ストリームには、Reader系とWriter系のオブジェクトが用意されたことを入出力の基本知識のマトリックス図で説明しました。

BufferedReader系とBufferedWriter系を用いたサンプルを以下に示します。

文字コードを考慮したサンプル
package jp.co.yourcompany.education.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

import jp.co.yourcompany.education.exception.ApplicationException;
import jp.co.yourcompany.education.log.InitApplication;

/**
 * 文字ストリーム(java.io.Reader,java.io.Writer)クラスの
 * 学習用サンプルクラス
 * @author raita.kuwabara
 */
public class JavaIOCharacterStreamSample{
    /**
     * ロガーインスタンス
     */
    public static final Logger log = Logger.getLogger( JavaIOCharacterStreamSample.class.getName() );

    /**
     * educationプロジェクトファイルデータ格納先ディレクトリ
     */
    public static final String PROJECT_DATA_DIR = "c:/projects/education/data";

    /**
     * 入力データ格納先ディレクトリ
     */
    public static final String INPUT_DATA_DIR = JavaIOCharacterStreamSample.PROJECT_DATA_DIR  + "/input";

    /**
     * 出力データ格納先ディレクトリ
     */
    public static final String OUTPUT_DATA_DIR = JavaIOCharacterStreamSample.PROJECT_DATA_DIR  + "/output";

    /**
     * デフォルトコンストラクタ
     * ログの初期化
     */
    public JavaIOCharacterStreamSample(){
        InitApplication app = InitApplication.getInstance();
        app.init();
    }

    /**
     * 入出力ファイルのサンプル
     */
    public void execAllSample(){
        try {
            log.info("ファイルエンコード指定あり");
            characterFileSampleByEncoding();

        } catch (ApplicationException e) {
            log.severe("テキストデータの操作でエラーが発生したため異常終了しました。");
            log.log( Level.SEVERE , "例外内容" , e );
        }
        log.info("テキストデータの操作は正常終了しました。");
    }


    /**
     * サンプル文字データを別ファイルに出力する。
     * 日本語文字列の無いファイルのみしか適用できない。
     * @throws ApplicationException ファイルの例外発生時
     */
    private void characterFileSampleByEncoding() throws ApplicationException {
        final String readFile = INPUT_DATA_DIR + "/character.txt";
        final String writeFile = OUTPUT_DATA_DIR + "/character3.txt";


        try(
            FileInputStream fis = new FileInputStream( readFile );
            BufferedReader br = new BufferedReader(new InputStreamReader( fis , "SJIS") );

            FileOutputStream fos = new FileOutputStream( writeFile );
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( fos , "SJIS") );

        ){

            String line = null;
            while ( ( line = br.readLine() ) !=null){
                bw.write( line );
                bw.newLine();
            }

        } catch (FileNotFoundException e) {
            log.log( Level.SEVERE , "指定されたファイル{0}が存在しません。" , new String[] { readFile }  );
            log.log( Level.SEVERE , "例外内容" , e );
        } catch (IOException e) {
            log.log( Level.SEVERE , "入力ファイル:{0}" , new String[] { readFile }  );
            log.log( Level.SEVERE , "出力ファイル{0}:" , new String[] { writeFile }  );
            log.log( Level.SEVERE , "例外内容" , e );
        }
    }

    /**
     * javacコマンドから実行されるメインメソッド
     * @param arags 引数不要
     */
    public static final void main( String[] args){
        JavaIOCharacterStreamSample sample = new JavaIOCharacterStreamSample();
        sample.execAllSample();
    }
}
						

重要文字コードを指定できるjava.ioパッケージは、InputStreamReaderとOutputStreamReaderです。
これは、バイトストリームから文字ストリームへの橋渡しの役目を持ちますとJavaAPIに記載されています。

そして、InputSreamRader及びOutputStreamRaderのコンストラクタの引数は、InputStream及びOutputStreamです。

結果残念な事に、文字ストリーム用ファイル入出力FileReaderオブジェクト、FileWriterオブジェクトが出現しません。

そのため、システム開発でファイル読み込み及び読み込みにFileReader及びFileWriterオブジェクトが出現したら、
文字化けの可能性が高いコードといえます。

唯一のメリットは、メソッドreadLineにより、行単位で文字を操作することが簡易になる事です。

日本においては、ほぼバグソースとなりうる残念なソースも参考のため、記載しておきます。

文字コードを考慮していない文字化けが発生しやすいサンプル
    /**
     * サンプル文字データを文字コードを指定せずに出力する。
     * @throws ApplicationException ファイルの例外発生時
     * @deprecated 文字コードを指定していないので日本語のテキストファイルは化ける。
     */
    private void characterFileSampleByDefault() throws ApplicationException {
        final String readFile = INPUT_DATA_DIR + "/character.txt";
        final String writeFile = OUTPUT_DATA_DIR + "/character2.txt";

        try(
            FileReader fr = new FileReader( readFile );
            BufferedReader br = new BufferedReader( fr );
            FileWriter fw = new FileWriter( writeFile );
            BufferedWriter bw = new BufferedWriter( fw );
        ){

            String line = null;
            while ( ( line = br.readLine() ) !=null){
                bw.write( line );
                bw.newLine();
            }

        } catch (FileNotFoundException e) {
            log.log( Level.SEVERE , "指定されたファイル{0}が存在しません。" , new String[] { readFile }  );
            log.log( Level.SEVERE , "例外内容" , e );
        } catch (IOException e) {
            log.log( Level.SEVERE , "入力ファイル:{0}" , new String[] { readFile }  );
            log.log( Level.SEVERE , "出力ファイル{0}:" , new String[] { writeFile }  );
            log.log( Level.SEVERE , "例外内容" , e );
        }
    }
				

英語を母国語とした、システムでは上記ソースは文字ストリームで構成されシンプルなオブジェクトですが、
FileReader,BufferdReaderに文字コードが設定できない点は、Jdk1.1API作成時の設計ミスと思われても仕方がないです。

サンプルのダウンロードと実行方法

  • java_sample19.zipファイルを「c:/download/java/samples/」に保存して下さい。
  • java_sample19.zipファイルを「c:/projects」配下に展開して下さい。
  • コマンドプロンプトを起動して、「sample19.bat」を実行して下さい。
  • javac,jar,javaが実行されてJavaIOCharacterStreamSampleが実行されます。
  • 「c:/projects/education/logs」配下のログの実行結果を確認して下さい。
  • 「c:/projects/education/input/character.txt」ファイルがそれぞれ、
    「c:/projects/education/output/character2.txt」「「c:/projects/education/output/character3.txt」」にコピーされていることを確認して下さい。
  • Linux,Unix,iOSの方はバッチファイルはお手数ですが作成して下さい。改行コードが「CRLF」の点ご留意ください。

参考にするAPI