1概要



BufferedReader


は、文字入力ストリームからのテキストの読み取りを簡単にするクラスです。

テキストデータの効率的な読み取りを可能にするために文字をバッファします。

このチュートリアルでは、

BufferedReader

クラスの使用方法を見ていきましょう


_.

_


2

BufferedReader


を使用する場合

一般に、

BufferedReader

は、ファイル、ソケット、その他のものなど、あらゆる種類の入力ソースからテキストを読みたい場合に便利です。

簡単に言えば、** 文字の塊を読み込んで内部バッファに格納することで、入出力操作の数を最小限に抑えることができます。


2.1. 他のリーダーのバッファリング

ほとんどのJava I/Oクラスと同様に、


__ BufferedReader


implements




Decoratorパターン、





はコンストラクタ内で

Reader

が必要であることを意味します。


このようにして、

Reader__実装のインスタンスを柔軟に拡張できます。バッファリング機能付き

BufferedReader reader =
  new BufferedReader(new FileReader("src/main/resources/input.txt"));

しかし、バッファリングが問題にならない場合は、____FileReaderを直接使用することができます。

FileReader reader =
  new FileReader("src/main/resources/input.txt");

バッファリングに加えて、**

__ BufferedReader


alsoは、ファイルを行単位で読み込むための優れたヘルパー関数をいくつか提供します。そのため、


FileReaderを直接使用するほうが簡単に見えるかもしれませんが、

BufferedReader__は大きな助けになります。


2.2. ストリームのバッファリング

一般的に、あらゆる種類の入力ストリームを基になるソースとして扱うように

BufferedReader

を設定することができます。

InputStreamReader

を使用してそれをコンストラクタでラップすることができます。

BufferedReader reader =
  new BufferedReader(new InputStreamReader(System.in));

上記の例では、通常はキーボードからの入力に対応する

__System.inから読み取ります。同様に、ソケット、ファイル、または考えられるタイプのテキスト入力から読み取るための入力ストリームを渡すことができます。唯一の前提条件は、それに適した

InputStream__実装があることです。


2.3. BufferedReaderとScanner

代わりに、

Scanner

クラスを使用して__BufferedReader.と同じ機能を実現できます。

ただし、これら2つのクラスには大きな違いがあり、ユースケースに応じて、これらのクラスが多少なりとも便利になります。


  • BufferedReader

    は同期されていますが(スレッドセーフ)、Scannerは同期していません


  • __Scanner

    __は通常の方法でプリミティブ型と文字列を解析する


**

BufferedReader

はバッファのサイズを変更することを可能にします

スキャナは固定バッファサイズを持っています
**

BufferedReader

のデフォルトバッファサイズが大きくなりました


  • Scanner



    IOException

    を隠し、

    BufferedReader

    は強制的に

扱う
**

BufferedReader

は通常

Scanner

より速いです。

解析せずにデータを読み取る

これらを念頭に置いて、ファイル内の個々のトークンを解析する場合、

Scanner



__BufferedReaderよりも少し自然に感じられます。ただし、一度に1行ずつ読み取るのは、


BufferedReaderが

__輝く場所です。

必要に応じて、https://www.baeldung.com/java-scanner[

Scanner

]のガイドもあります。


3

BufferedReader


でテキストを読む

テキストファイルから読み込むための____BufferReaderの構築、使用、破棄の全プロセスを見ていきましょう。


3.1.

BufferedReader


を初期化する

まず、**

BufferedReader(Reader)

コンストラクタを使って

BufferedReader

を作成しましょう。

BufferedReader reader =
  new BufferedReader(new FileReader("src/main/resources/input.txt"));

このように

FileReader

をラップすることは、他の読者にアスペクトとしてバッファリングを追加するための良い方法です。

デフォルトでは、これは8 KBのバッファを使用します。ただし、もっと小さいブロックやもっと大きいブロックをバッファリングする場合は、

BufferedReader(Reader、int)

コンストラクタを使用できます。

BufferedReader reader =
  new BufferedReader(new FileReader("src/main/resources/input.txt")), 16384);

これはバッファサイズを16384バイト(16 KB)に設定します。

最適なバッファサイズは、入力ストリームの種類やコードが実行されているハードウェアなどの要因によって異なります。このため、理想的なバッファサイズを実現するには、実験して自分で見つけなければなりません。

ほとんどのハードウェアデバイスはブロックサイズとして2のべき乗を持っているので、バッファサイズとして2のべき乗を使用するのが最善です。

最後に、**


Files


ヘルパークラスを使用して

BufferedReader

を作成するもう1つの便利な方法があります。

java.nio


API:

BufferedReader reader =
  Files.newBufferedReader(Paths.get("src/main/resources/input.txt"))

手動で____FileReaderを作成してからラップする必要がないため、ファイルを読み込む場合はこれをバッファリングするのがいいでしょう。


3.2. 1行ずつ読む

次に、

readLine

メソッドを使用してファイルの内容を読みましょう。

public String readAllLines(BufferedReader reader) throws IOException {
    StringBuilder content = new StringBuilder();
    String line;

    while ((line = reader.readLine()) != null) {
        content.append(line);
        content.append(System.lineSeparator());
    }

    return content.toString();
}

  • もう少し簡単に言うと、Java 8で導入された

    __lines

    __methodを使って上記と同じことができます。

public String readAllLinesWithStream(BufferedReader reader) {
    return reader.lines()
      .collect(Collectors.joining(System.lineSeparator()));
}


3.3. ストリームを閉じる


BufferedReader

を使用した後、その

close()

メソッドを呼び出して、それに関連するすべてのシステムリソースを解放する必要があります。

try-with-resources

ブロックを使用すると、これは自動的に行われます。

try (BufferedReader reader =
       new BufferedReader(new FileReader("src/main/resources/input.txt"))) {
    return readAllLines(reader);
}


4その他の便利な方法

それでは、

BufferedReader.

で利用可能なさまざまな便利なメソッドに焦点を絞りましょう。


4.1. 1文字の読み方


__read()

__メソッドを使用して単一の文字を読み取ることができます。ストリームの最後まで、コンテンツ全体を文字ごとに読みましょう。

public String readAllCharsOneByOne(BufferedReader reader) throws IOException {
    StringBuilder content = new StringBuilder();

    int value;
    while ((value = reader.read()) != -1) {
        content.append((char) value);
    }

    return content.toString();
}

これは(ASCII値として返された)文字を読み込み、それらを

char

にキャストして結果に追加します。

read()

メソッドからの応答値-1で示されるストリームの終わりまでこれを繰り返します。


4.2. 複数の文字を読む

一度に複数の文字を読みたい場合は、メソッド

read(char[]cbuf、int off、int len)

を使用できます。

public String readMultipleChars(BufferedReader reader) throws IOException {
    int length;
    char[]chars = new char[length];
    int charsRead = reader.read(chars, 0, length);

    String result;
    if (charsRead != -1) {
        result = new String(chars, 0, charsRead);
    } else {
        result = "";
    }

    return result;
}

上記のコード例では、最大5文字をchar配列に読み込み、そこから文字列を構成します。読み取りの試行で文字が読み取られなかった場合(つまり、ストリームの終わりに達した場合)、単に空の文字列を返します。


4.3. スキップ文字


skip(long n)

メソッドを呼び出して、指定した数の文字をスキップすることもできます。

@Test
public void givenBufferedReader__whensSkipChars__thenOk() throws IOException {
    StringBuilder result = new StringBuilder();

    try (BufferedReader reader =
           new BufferedReader(new StringReader("1____2____3____4____5"))) {
        int value;
        while ((value = reader.read()) != -1) {
            result.append((char) value);
            reader.skip(2L);
        }
    }

    assertEquals("12345", result);
}

上記の例では、2つのアンダースコアで区切られた数字を含む入力文字列から読み取ります。数字だけを含む文字列を作成するために、


_skip

_

methodを呼び出してアンダースコアをスキップします。


4.4.

mark



reset



mark(int readAheadLimit)

および

__reset()


methodsメソッドを使用して、ストリーム内のある位置をマークして後で戻ることができます。やや不自然な例として、

mark()



reset()__を使用して、ストリームの先頭にあるすべての空白を無視しましょう。

@Test
public void givenBufferedReader__whenSkipsWhitespacesAtBeginning__thenOk()
  throws IOException {
    String result;

    try (BufferedReader reader =
           new BufferedReader(new StringReader("    Lorem ipsum dolor sit amet."))) {
        do {
            reader.mark(1);
        } while(Character.isWhitespace(reader.read()))

        reader.reset();
        result = reader.readLine();
    }

    assertEquals("Lorem ipsum dolor sit amet.", result);
}

上記の例では、

__ mark()


メソッドを使用して、先ほど読んだ位置にマークを付けます。値を1にすると、コードだけが1文字分のマークを記憶します。

最初の空白以外の文字が見つかったら、ストリーム全体を再処理する必要なくその文字に戻って読み直すことができるので、ここでは便利です。マークを付けないと、最後の文字列で


L__が失われます。


mark()



UnsupportedOperationException

をスローする可能性があるため、

markSupported()



__mark()を呼び出すコードに関連付けることは非常に一般的です。


ただし、実際には必要ありません。




markSupported()


alwaysが

BufferedReader __に対してtrueを返すからです。

もちろん、私たちは他の方法でもう少し上品に上記のことをすることができるかもしれません、そして実際には

__mark




reset__は非常に典型的な方法ではないです。ただし、先読みする必要がある場合は、確かに便利です。


5結論

このクイックチュートリアルでは、

BufferedReader

を使用した実用的な例で文字入力ストリームを読み取る方法を学びました。

最後に、例のソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-io[Githubで利用可能]です。