Question

Quelles sont les différences (le cas échéant) entre les deux approches suivantes tampon?

Reader r1 = new BufferedReader(new InputStreamReader(in, "UTF-8"), bufferSize);
Reader r2 = new InputStreamReader(new BufferedInputStream(in, bufferSize), "UTF-8");
Était-ce utile?

La solution

r1 est plus efficace. Le InputStreamReader lui-même ne dispose pas d'un grand tampon. Le BufferedReader peut être réglé pour avoir un tampon plus grand que InputStreamReader. Le InputStreamReader en r2 agirait comme un goulot d'étranglement.

Dans un écrou. Vous devriez lire les données à travers un entonnoir, et non par une bouteille


Mise à jour : voici un petit programme de référence, juste copy'n'paste'n'run il. Vous n'avez pas besoin de préparer des fichiers.

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

}

Résultats à mon Latitude E5500 avec un Seagate Momentus 7200.3 harddisk:

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

Autres conseils

r1 est également plus pratique lorsque vous lisez flux basé sur la ligne comme supports de BufferedReader méthode readLine. Vous ne devez pas lire le contenu dans une mémoire tampon de tableau de caractères ou les caractères un par un. Cependant, vous devez fonte r1 à BufferedReader ou utiliser explicitement ce type pour la variable.

J'utilise souvent cet extrait de code:

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

En réponse à la question de Ross Studtman dans le commentaire ci-dessus (mais aussi pertinente pour l'OP):

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

Le BufferedInputStream est superflu (et la performance des préjudices probablement dû à la copie étrangère). En effet, les caractères demandes de BufferedReader du InputStreamReader en gros morceaux en appelant InputStreamReader.read(char[], int, int), qui à son tour (par StreamDecoder) appelle InputStream.read(byte[], int, int) lire un grand bloc d'octets de la InputStream sous-jacent.

Vous pouvez vous convaincre que cela est si en exécutant le code suivant:

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

Vous verrez la sortie suivante:

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

Ceci démontre que la demande BufferedReader une grande partie des caractères de la InputStreamReader, ce qui demande une grande partie d'octets de la InputStream sous-jacent.

FWIW, si vous ouvrez un fichier en Java 8, vous pouvez utiliser le Files.newBufferedReader (chemin) . Je ne sais pas comment la performance se compare aux autres solutions décrites ici, mais au moins il pousse la décision de ce concept de tampon dans le JDK.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top