Debería amortiguar el InputStream o la InputStreamReader?
-
27-09-2019 - |
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");
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.