Java の BufferedReader を使った効率的なテキスト処理

JavaBeginner
オンラインで実践に進む

はじめに

この実験では、java.io パッケージの一部である Java の BufferedReader クラスを使用します。BufferedReader は、文字入力ストリームからテキストを読み取り、より良好なパフォーマンスのために文字をバッファリングします。このクラスは他のリーダークラスや入力ストリームをラップし、プログラムの全体的な効率とパフォーマンスを向上させることができます。BufferedReader のさまざまなコンストラクタ、メソッド、および使用例を調べて、その機能を理解します。

FileReader を使って BufferedReader を作成する

BufferedReader のコンストラクタは、Reader オブジェクトをパラメータとして取ります。デフォルトのエンコーディングでテキストファイルを読み取る FileReader を使って、リーダーを作成することができます。このステップでは、FileReader をラップすることで BufferedReader クラスを使ってファイルを読み取ります。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try {
            FileReader fileReader = new FileReader(path);
            BufferedReader bufferedReader = new BufferedReader(fileReader); //FileReader をラップして BufferedReader を作成する
            // ここにファイルからデータを読み取るコードを追加する

            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

コードを実行するには、javac BufferedReaderDemo.java でファイルをコンパイルし、その後 java BufferedReaderDemo で実行します。

ストリームとともに BufferedReader を使用する

入力ストリームをソースとして BufferedReader を作成することもできます。このステップでは、InputStreamReaderBufferedReader でラップして、System.in からデータを読み取ります。これにより、キーボードを使って入力したデータが読み取られます。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BufferedReaderDemo {
    public static void main(String[] args) {
        try {
            InputStreamReader isr = new InputStreamReader(System.in);
            BufferedReader bufferedReader = new BufferedReader(isr); //BufferedReader を作成する
            System.out.println("何か入力してください:");
            String line = bufferedReader.readLine(); //コンソールから入力を読み取る
            System.out.println("入力内容:" + line); //入力内容を表示する

            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ストリームをクローズする

常に BufferedReaderclose() メソッドを使用して、リーダーに関連付けられたすべてのシステム リソースを解放する必要があります。コードを簡略化するために、try-with-resources ブロックを使用して、ストリームを自動的にクローズすることができます。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            // ここにファイルからデータを読み取るコードを追加する

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

BufferedReader と Scanner の比較

ScannerBufferedReader の両方を使って外部ソースからデータを読み取ることができます。ただし、これら 2 つのクラスにはいくつかの違いがあります。このステップでは、いくつかの主な違いを比較します。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader);
             Scanner scanner = new Scanner(fileReader)) {
            long startTime = System.nanoTime();
            // BufferedReader を使ってファイルを読み取る
            bufferedReader.readLine();
            while (bufferedReader.readLine()!= null) ;
            long endTime = System.nanoTime();
            System.out.println("BufferedReader による処理時間 : " + (endTime - startTime) + "ns");

            startTime = System.nanoTime();
            // Scanner を使ってファイルを読み取る
            scanner.nextLine();
            while (scanner.hasNextLine()) scanner.nextLine();
            endTime = System.nanoTime();
            System.out.println("Scanner による処理時間 : " + (endTime - startTime) + "ns");

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

このコードは、同じファイルからデータを読み取る際の BufferedReaderScanner による処理時間を比較します。計測時間は異なりますが、出力結果からどちらが長い時間を要するかを知ることができます。

ファイルを 1 行ずつ読み取る

BufferedReader クラスには、データを読み取るためのいくつかのメソッドが用意されています。readLine() メソッドは 1 行ずつ読み取ります。このメソッドは、ストリームの末尾に達した場合に null を返します。このステップでは、BufferedReader.readLine() を使ってファイルを読み取ります。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            String line;
            while ((line = bufferedReader.readLine())!= null) {
                System.out.println(line);
            }

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

ファイルから 1 文字ずつ読み取る

BufferedReader クラスの read() メソッドを使用することで、1 文字ずつ読み取ることもできます。このメソッドは、読み取った文字を整数として返します。ストリームの末尾に達した場合、-1 を返します。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            int charRead;
            while ((charRead = bufferedReader.read())!= -1) {
                System.out.print((char) charRead);
            }

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

ファイルから複数の文字を読み取る

read() メソッドを使用すると、一度に複数の文字を読み取ることができます。データを格納する char 配列を渡す必要があります。また、char 配列の開始インデックスを示すオフセットを使用する必要があります。格納されたデータはこのインデックスから始まります。読み取る文字の最大長も指定する必要があります。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            char[] charArr = new char[5];
            bufferedReader.read(charArr, 0, 5);
            System.out.print(charArr);

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

文字のスキップ

BufferedReader クラスには、文字をスキップするための skip() メソッドがあります。このメソッドは long 型のパラメータを受け取ります。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            int charRead;
            StringBuilder sb = new StringBuilder();
            while ((charRead = bufferedReader.read())!= -1) {
                if (charRead!= '*') {
                    sb.append((char) charRead);
                } else {
                    bufferedReader.skip(1);
                }
            }
            System.out.println(sb);

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

マークとリセット

BufferedReader クラスは、特定の文字をマークするための mark() メソッドを提供します。将来のいつでも、reset() メソッドを使用してこのマークされた文字に戻ることができます。mark() メソッドは、マークが無効になる前に読み取ることができる最大バイト数を表す整数を入力として受け取ります。

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

public class BufferedReaderDemo {
    public static void main(String[] args) {
        String path = "path/to/your/file.txt";
        try (FileReader fileReader = new FileReader(path);
             BufferedReader bufferedReader = new BufferedReader(fileReader)) {

            char[] charArr = new char[5];
            charArr[0] = (char) bufferedReader.read();
            charArr[1] = (char) bufferedReader.read();

            bufferedReader.mark(10);
            bufferedReader.skip(1);
            charArr[2] = (char) bufferedReader.read();
            charArr[3] = (char) bufferedReader.read();
            charArr[4] = (char) bufferedReader.read();
            System.out.println(charArr);

            bufferedReader.reset();
            char asterisk = (char) bufferedReader.read();
            System.out.print(asterisk);

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

まとめ

この実験では、Java の BufferedReader クラスを使用して文字入力ストリームからテキストを読み取りました。他のリーダークラスや入力ストリームを BufferedReader でラップすることで、パフォーマンスと効率を向上させる方法を学びました。ファイルから 1 文字と複数の文字を読み取る、文字をスキップする、ファイル内の位置をマークしてリセットする、BufferedReader と Scanner クラスを比較するなどのトピックを扱いました。また、try-with-resources ブロックを使用してストリームを自動的にクローズし、メモリリークを回避しました。