Frage

Was sind die Unterschiede (falls vorhanden) zwischen den beiden folgenden Puffer Ansätze?

Reader r1 = new BufferedReader(new InputStreamReader(in, "UTF-8"), bufferSize);
Reader r2 = new InputStreamReader(new BufferedInputStream(in, bufferSize), "UTF-8");
War es hilfreich?

Lösung

r1 ist effizienter. Die InputStreamReader selbst hat keinen großen Puffer. Der BufferedReader kann eingestellt werden, einen größeren Puffer als InputStreamReader haben. Die InputStreamReader in r2 würde als Engpass handeln.

In einer Mutter. Sie die Daten durch einen Trichter lesen sollen, nicht durch eine Flasche


Aktualisieren : hier ist ein kleines Benchmark-Programm, nur um es copy'n'paste'n'run. Sie müssen nicht vorbereiten Dateien benötigen.

package com.stackoverflow.q3459127;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

public class Test {

    public static void main(String... args) throws Exception {

        // Init.
        int bufferSize = 10240; // 10KB.
        int fileSize = 100 * 1024 * 1024; // 100MB.
        File file = new File("/temp.txt");

        // Create file (it's also a good JVM warmup).
        System.out.print("Creating file .. ");
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(file));
            for (int i = 0; i < fileSize; i++) {
                writer.write("0");
            }
            System.out.printf("finished, file size: %d MB.%n", file.length() / 1024 / 1024);
        } finally {
            if (writer != null) try { writer.close(); } catch (IOException ignore) {}
        }

        // Read through funnel.
        System.out.print("Reading through funnel .. ");
        Reader r1 = null;        
        try {
            r1 = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"), bufferSize);
            long st = System.nanoTime();
            for (int data; (data = r1.read()) > -1;);
            long et = System.nanoTime();
            System.out.printf("finished in %d ms.%n", (et - st) / 1000000);
        } finally {
            if (r1 != null) try { r1.close(); } catch (IOException ignore) {}
        }

        // Read through bottle.
        System.out.print("Reading through bottle .. ");
        Reader r2 = null;        
        try {
            r2 = new InputStreamReader(new BufferedInputStream(new FileInputStream(file), bufferSize), "UTF-8");
            long st = System.nanoTime();
            for (int data; (data = r2.read()) > -1;);
            long et = System.nanoTime();
            System.out.printf("finished in %d ms.%n", (et - st) / 1000000);
        } finally {
            if (r2 != null) try { r2.close(); } catch (IOException ignore) {}
        }

        // Cleanup.
        if (!file.delete()) System.err.printf("Oops, failed to delete %s. Cleanup yourself.%n", file.getAbsolutePath());
    }

}

Ergebnisse an meinem Latitude E5500 mit einem Seagate Momentus 7200.3 Festplatte:

Creating file .. finished, file size: 99 MB.
Reading through funnel .. finished in 1593 ms.
Reading through bottle .. finished in 7760 ms.

Andere Tipps

r1 ist auch bequemer, wenn Sie zeilenbasierten Stream gelesen als BufferedReader unterstützt Methode readLine. Sie müssen nicht Inhalt in ein char-Array Puffer gelesen oder verkohlt eins nach dem anderen. Sie haben jedoch zu gegossenen r1 zu BufferedReader oder diese Art verwenden, explizit für die Variable.

Ich habe oft die Code-Schnipsel verwenden:

BufferedReader br = ...
String line;
while((line=br.readLine())!=null) {
  //process line
}

Als Reaktion auf Ross Studtman Frage in dem Kommentar oben (aber auch relevant für die OP):

BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputSream(inputStream), "UTF-8"));

Die BufferedInputStream ist überflüssig (und wahrscheinlich Harms Leistung durch Fremd Kopieren). Dies liegt daran, dass die BufferedReader Anfragen Zeichen aus dem InputStreamReader in großen Stücken durch den Aufruf InputStreamReader.read(char[], int, int), die wiederum (durch StreamDecoder) rufen InputStream.read(byte[], int, int) einen großen Block von Bytes aus dem zugrunde liegenden InputStream zu lesen.

Sie können sich selbst davon überzeugen, dass dies so ist durch den folgenden Code ausführen:

new BufferedReader(new InputStreamReader(new ByteArrayInputStream("Hello world!".getBytes("UTF-8")) {

    @Override
    public synchronized int read() {
        System.err.println("ByteArrayInputStream.read()");
        return super.read();
    }

    @Override
    public synchronized int read(byte[] b, int off, int len) {
        System.err.println("ByteArrayInputStream.read(..., " + off + ", " + len + ')');
        return super.read(b, off, len);
    }

}, "UTF-8") {

    @Override
    public int read() throws IOException {
        System.err.println("InputStreamReader.read()");
        return super.read();
    }

    @Override
    public int read(char[] cbuf, int offset, int length) throws IOException {
        System.err.println("InputStreamReader.read(..., " + offset + ", " + length + ')');
        return super.read(cbuf, offset, length);
    }

}).read(); // read one character from the BufferedReader

Sie werden die folgende Ausgabe:

InputStreamReader.read(..., 0, 8192)
ByteArrayInputStream.read(..., 0, 8192)

Dies zeigt, dass der BufferedReader einen großen Teil von Zeichen aus dem InputStreamReader fordert, was wiederum einen großen Teil von Bytes aus dem zugrunde liegenden InputStream anfordert.

FWIW, wenn Sie eine Datei öffnen in Java 8, können Sie die Files.newBufferedReader (Path) . Ich weiß nicht, wie die Leistung zu den anderen Lösungen vergleicht hier beschrieben, aber zumindest schiebt er die Entscheidung, was Konstrukt in das JDK zu puffern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top