Pregunta

¿Cuáles son las diferencias (si las hay) entre los dos siguientes enfoques de amortiguación?

Reader r1 = new BufferedReader(new InputStreamReader(in, "UTF-8"), bufferSize);
Reader r2 = new InputStreamReader(new BufferedInputStream(in, bufferSize), "UTF-8");
¿Fue útil?

Solución

r1 es más eficiente. El InputStreamReader en sí no tiene un buffer de gran tamaño. El BufferedReader se puede configurar para tener un buffer más grande que InputStreamReader. El InputStreamReader en r2 actuaría como un cuello de botella.

En una tuerca:. Usted debe leer los datos a través de un embudo, no a través de una botella


Actualizar : aquí hay un pequeño programa de referencia, al igual que copy'n'paste'n'run. No es necesario para preparar los archivos.

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

}

Los resultados en mi Latitude E5500 con una Seagate Momentus 7200.3 disco duro:

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

Otros consejos

r1 también es más conveniente cuando se lee la corriente basado en líneas como soportes BufferedReader readLine método. Usted no tiene que leer el contenido en un búfer matriz de caracteres o chamusca uno por uno. Sin embargo, usted tiene que r1 fundido a BufferedReader o utilizar ese tipo de forma explícita para la variable.

A menudo utilizo este fragmento de código:

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

En respuesta a la pregunta de Ross Studtman en el comentario anterior (pero también es relevante para el OP):

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

El BufferedInputStream es superflua (y es probable que el rendimiento daños debido a la copia extraña). Esto se debe a que los personajes peticiones BufferedReader de la InputStreamReader en grandes trozos de InputStreamReader.read(char[], int, int) llamar, que a su vez (a través de StreamDecoder) llama InputStream.read(byte[], int, int) para leer un gran bloque de bytes desde el InputStream subyacente.

Puede convencerse de que esto es así, ejecute el siguiente código:

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

Se verá el siguiente resultado:

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

Esto demuestra que el BufferedReader solicita una gran parte de los personajes de la InputStreamReader, que a su vez solicita una gran parte de bytes desde el InputStream subyacente.

Fwiw, si usted está abriendo un archivo en Java 8, se puede utilizar el

scroll top