Leitfaden für BufferedReader

Anleitung zu BufferedReader

1. Überblick

BufferedReader ist eine Klasse, die das Lesen von Text aus einem Zeicheneingabestream vereinfacht. Es puffert die Zeichen, um ein effizientes Lesen von Textdaten zu ermöglichen.

In diesem Tutorial werden wir uns ansehen, wie dieBufferedReader-Klasse. verwendet wird

2. Wann wirdBufferedReader verwendet?

Im Allgemeinen istBufferedReader nützlich, wenn wir Text aus einer beliebigen Eingabequelle lesen möchten, egal ob es sich um Dateien, Sockets oder etwas anderes handelt.

Einfach ausgedrückt,it enables us to minimize the number of I/O operations by reading chunks of characters and storing them in an internal buffer. Während der Puffer Daten enthält, liest der Leser daraus und nicht direkt aus dem zugrunde liegenden Stream.

2.1. Einen anderen Leser puffern

Wie die meisten Java-E / A-KlassenBufferedReader implementsDecorator pattern, meaning it expects a Reader in its constructor. Auf diese Weise können wir eine Instanz einerReader-Implementierung flexibel mit Pufferfunktionen erweitern:

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

Wenn uns das Puffern jedoch nichts ausmacht, können wir einfach einFileReader direkt verwenden:

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

Zusätzlich zur Pufferung werdenBufferedReader also provides some nice helper functions for reading files line-by-line. Auch wenn es einfacher erscheint,FileReader direkt zu verwenden, kannBufferedReader eine große Hilfe sein.

2.2. Einen Stream puffern

Im Allgemeinen sindwe can configure BufferedReader to take any kind of input stream as an underlying source. Wir können es mitInputStreamReader machen und es in den Konstruktor einschließen:

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

Im obigen Beispiel lesen wir ausSystem.in , was normalerweise der Eingabe über die Tastatur entspricht. In ähnlicher Weise könnten wir einen Eingabestream zum Lesen aus einem Socket, einer Datei oder einer beliebigen vorstellbaren Art von Texteingabe übergeben. Die einzige Voraussetzung ist, dass eine geeigneteInputStream-Implementierung dafür vorhanden ist.

2.3. BufferedReader vs Scanner

Alternativ könnten wir die KlasseScanner verwenden, um die gleiche Funktionalität wie beiBufferedReader. zu erreichen

Es gibt jedoch signifikante Unterschiede zwischen diesen beiden Klassen, die sie für uns je nach Anwendungsfall mehr oder weniger praktisch machen können:

  • BufferedReader ist synchronisiert (threadsicher), Scanner nicht

  • Scanner cannt primitive Typen und Zeichenfolgen mit regulären Ausdrücken

  • BufferedReader ermöglicht das Ändern der Puffergröße, während der Scanner eine feste Puffergröße hat

  • BufferedReader hat eine größere Standardpuffergröße

  • Scanner verbirgtIOException, währendBufferedReader uns zwingt, damit umzugehen

  • BufferedReader ist normalerweise schneller alsScanner, da nur die Daten gelesen werden, ohne sie zu analysieren

In diesem Sinneif we are parsing individual tokens in a file, then Scanner will feel a bit more natural than BufferedReader. But, just reading a line at a time is where BufferedReader shines.

Bei Bedarf haben wir aucha guide on Scanner.

3. Lesen von Text mitBufferedReader

Lassen Sie uns den gesamten Prozess des Erstellens, Zerstörens und Zerstörens einesBufferReader durchlaufen, um es aus einer Textdatei zu lesen.

3.1. Initialisierung von aBufferedReader

Erstenslet’s create a BufferedReader using its BufferedReader(Reader) constructor:

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

Das Umschließen derFileReader auf diese Weise ist eine gute Möglichkeit, anderen Lesern Pufferung als Aspekt hinzuzufügen.

Standardmäßig wird ein Puffer von 8 KB verwendet. Wenn wir jedoch kleinere oder größere Blöcke puffern möchten, können wir den KonstruktorBufferedReader(Reader, int)verwenden:

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

Dadurch wird die Puffergröße auf 16384 Byte (16 KB) festgelegt.

Die optimale Puffergröße hängt von Faktoren wie dem Typ des Eingabestreams und der Hardware ab, auf der der Code ausgeführt wird. Aus diesem Grund müssen wir die ideale Puffergröße durch Experimentieren selbst ermitteln.

Es ist am besten, Potenzen von 2 als Puffergröße zu verwenden, da die meisten Hardwaregeräte eine Potenz von 2 als Blockgröße haben.

Schließlichthere is one more handy way to create a BufferedReader using the Files helper class ausjava.nioAPI:

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

Erstellen Sie es like Dies ist eine gute Möglichkeit zum Puffern, wenn Sie eine Datei lesen möchten, da wir nicht zuerst manuell einFileReader erstellen und es dann umbrechen müssen.

3.2. Zeile für Zeile lesen

Lesen Sie als Nächstes den Inhalt der Datei mit der MethodereadLine:

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();
}

We can do the same thing as above using the lines method introduced in Java 8ist etwas einfacher:

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

3.3. Stream schließen

Nachdem wir dieBufferedReader verwendet haben, müssen wir dieclose()-Methode aufrufen, um alle damit verbundenen Systemressourcen freizugeben. Dies erfolgt automatisch, wenn wir einentry-with-resources-Block verwenden:

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

4. Andere nützliche Methoden

Konzentrieren wir uns nun auf verschiedene nützliche Methoden, die inBufferedReader. verfügbar sind

4.1. Ein einzelnes Zeichen lesen

Wir können dieread() -Smethod verwenden, um ein einzelnes Zeichen zu lesen. Lesen wir den gesamten Inhalt zeichenweise bis zum Ende des Streams:

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();
}

Dadurch werden die Zeichen (als ASCII-Werte zurückgegeben) gelesen, inchar umgewandelt und an das Ergebnis angehängt. Wir wiederholen dies bis zum Ende des Streams, was durch den Antwortwert -1 derread()-Methode angezeigt wird.

4.2. Mehrere Zeichen lesen

Wenn wir mehrere Zeichen gleichzeitig lesen möchten, können wir die Methoderead(char[] cbuf, int off, int len) verwenden:

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;
}

Im obigen Codebeispiel lesen wir bis zu 5 Zeichen in ein char-Array und erstellen daraus eine Zeichenfolge. In dem Fall, dass bei unserem Leseversuch keine Zeichen gelesen wurden (d. H. Wir haben das Ende des Streams erreicht. Wir geben einfach eine leere Zeichenfolge zurück.

4.3. Zeichen überspringen

Wir können auch eine bestimmte Anzahl von Zeichen überspringen, indem wir die Methodeskip(long n)aufrufen:

@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);
}

Im obigen Beispiel lesen wir aus einer Eingabezeichenfolge, die durch zwei Unterstriche getrennte Zahlen enthält. Um eine Zeichenfolge zu erstellen, die nur die Zahlen enthält, überspringen wir die Unterstriche, indem wir die sm-Methodeskip aufrufen.

4.4. mark undreset

Wir können die Methodenmark(int readAheadLimit) undreset() verwenden, um eine Position im Stream zu markieren und später darauf zurückzukommen. Verwenden wir als etwas erfundenes Beispielmark() undreset(), um alle Leerzeichen am Anfang eines Streams zu ignorieren:

@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);
}

Im obigen Beispiel verwenden wir diemark() -Smethodik, um die gerade gelesene Position zu markieren. Ein Wert von 1 bedeutet, dass nur der Code die Markierung für ein Zeichen vorwärts speichert. It’s handy here because, once we see our first non-whitespace character, we can go back and re-read that character without needing to reprocess the whole stream. Without having a mark, we’d lose the L in our final string.

Damark()UnsupportedOperationException auslösen kann, ist es ziemlich üblich,markSupported() mit Code zu verknüpfen, dermark().  aufruft. Wir brauchen ihn hier jedoch nicht. That’s because markSupported() always returns true for BufferedReader.

Natürlich könnten wir das oben Genannte auf andere Weise etwas eleganter machen, und tatsächlich sindmark andresetkeine sehr typischen Methoden. They certainly come in handy, though, when there is a need to look ahead.

5. Fazit

In diesem kurzen Tutorial haben wir in einem praktischen Beispiel mitBufferedReader gelernt, wie man Zeicheneingabestreams liest.

Schließlich ist der Quellcode für die Beispieleover on Github verfügbar.