2010-08-11 10 views

cevap

26

r1 daha etkilidir. InputStreamReader'un kendisi büyük bir arabellek içermiyor. BufferedReader, InputStreamReader'dan daha büyük bir arabelleğe sahip olacak şekilde ayarlanabilir. r2 numaralı telefondan InputStreamReader darboğaz gibi davranır.

Somunla: Verileri bir şişeden değil, bir huni yoluyla okumalısınız.


Güncelleme: Burada küçük bir kriter programı, sadece copy'n'paste'n'run. Dosyaları hazırlamanıza gerek yoktur. Bir Seagate Momentus 7200.3 harddisk ile Latitude E5500 de

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

} 

Sonuçlar: BufferedReaderreadLine yöntemini destekler gibi hat tabanlı akışı okurken

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

Temeldeki InputStream bir FileInputStream ise, iki Okuyucu, tüm okuma süreci boyunca farklı disk okuma değerleri gerçekleştirir mi? – bdkosher

+0

Ben perfmon kullanarak kontrol ettim, fark edilebilir farklar görmüyorum.Bir karşılaştırma kodu snippet'i eklemek için cevabı yakında güncelleyeceğim. – BalusC

+1

Paket adı gibi büyük :) –

5

r1 da daha uygundur. İçeriği bir char dizisi arabelleğine veya karakterlerine tek tek okumak zorunda değilsiniz. Ancak, r1'u BufferedReader'a dökmeniz veya bu tür için değişkeni açıkça kullanmanız gerekir.

Sık sık bu kod parçacığını kullanın:

yukarıdaki yorumda Ross Studtman sorusuna cevaben
BufferedReader br = ... 
String line; 
while((line=br.readLine())!=null) { 
    //process line 
} 
0

(ama OP zamanda ilgili): (

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

BufferedInputStream gereksiz olduğu ve Muhtemelen gereksiz kopyalama nedeniyle performansa zarar verir). Bunun nedeni BufferedReader, InputStreamReader.read(char[], int, int) numaralı çağırarak, numaralı çağırarak, büyük karakterleri karakterleri, , InputStream.read(byte[], int, int), altta yatan InputStream büyük bir bayt bloğu okumak için çağırır.

Bu aşağıdaki kodu çalıştırarak olduğunu kendinizi ikna edebilirsiniz:

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 

Aşağıdaki çıktıyı göreceksiniz:

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

Bu gösteriyor ki karakterlerden BufferedReader istekleri Büyük bir bölümü InputStreamReader'dan itibaren, temel olarak InputStream'dan büyük bir bayt yığını talep eder. Eğer Java 8'de bir dosyayı açıyorsunuz eğer

+0

Ve 'BufferedInputStream' kullanırsanız, büyük yığınlarda" InputStream "den veri ister ve" Readers "ın daha küçük isteklerini arabelleğinden çıkarır. Bu 'gereksiz' değil. – EJP

+0

@EJP: "BufferedReader", "InputStreamReader" öğesinden büyük bloklar istediği için örnek kod parçamdaki (arabellek kodumdaki ilk kod bloğu) "BufferedInputStream" ifadesinin gereksiz olması nedeniyle gereksizdir. 'InputStreamReader' ile alttaki 'InputStream' arasındaki' BufferedInputStream' eklentisi, herhangi bir performans artışı almadan sadece ek yük ekler. –

1

FWIW, sen Files.newBufferedReader(Path) kullanabilirsiniz. Performansın burada açıklanan diğer çözümlerle nasıl karşılaştırıldığını bilmiyorum, ancak en azından JDK'ya hangi yapının tamponlanacağı kararını zorluyor.

İlgili konular