2010-08-11 24 views
22

निम्नलिखित दो बफरिंग दृष्टिकोणों के बीच मतभेद (यदि कोई हैं) क्या हैं?क्या मुझे इनपुटस्ट्रीम या इनपुटस्ट्रीम रीडर को बफर करना चाहिए?

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

उत्तर

26

r1 अधिक कुशल है। InputStreamReader में कोई बड़ा बफर नहीं है। BufferedReader को InputStreamReader से बड़ा बफर रखने के लिए सेट किया जा सकता है। InputStreamReaderr2 में एक बाधा के रूप में कार्य करेगा।

अखरोट में: आपको एक बोतल के माध्यम से डेटा को फ़नल के माध्यम से पढ़ना चाहिए।


अद्यतन: यहाँ एक छोटे से बेंचमार्क कार्यक्रम है, बस यह copy'n'paste'n'run। आपको फाइलें तैयार करने की आवश्यकता नहीं है।

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

} 

एक Seagate Momentus 7200.3 हार्डडिस्क के साथ अपने अक्षांश E5500 पर परिणाम:

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

यदि अंतर्निहित इनपुटस्ट्रीम एक फ़ाइल इनपुटपुट था, तो क्या दो पाठक डिस्क की अलग-अलग मात्रा में पूरी पढ़ाई प्रक्रिया में पढ़ते हैं? – bdkosher

+0

मैंने पेर्फोन का उपयोग करके इसे चेक किया, मुझे ध्यान देने योग्य अंतर दिखाई नहीं दे रहे हैं।मैं बेंचमार्क कोड स्निपेट को शामिल करने के लिए जल्द ही उत्तर अपडेट कर दूंगा। – BalusC

+1

पैकेज नाम के लिए बड़ा बड़ा :) –

5

r1 जब आप लाइन पर आधारित स्ट्रीम पढ़ें BufferedReaderreadLine विधि का समर्थन करता है के रूप में भी और अधिक सुविधाजनक है। आपको सामग्री को चार सरणी बफर या वर्णों में एक-एक करके पढ़ने की आवश्यकता नहीं है। हालांकि, आपको r1BufferedReader पर डालना होगा या चर के लिए स्पष्ट रूप से उस प्रकार का उपयोग करना होगा।

मैं अक्सर इस कोड स्निपेट का उपयोग करें:

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

ऊपर टिप्पणी में रॉस Studtman के प्रश्न के उत्तर में (लेकिन यह भी ओ पी के लिए प्रासंगिक):

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

BufferedInputStream ज़रूरत से ज़्यादा है (और संभावित प्रतिलिपि के कारण प्रदर्शन को नुकसान पहुंचा सकता है)। ऐसा इसलिए है क्योंकि BufferedReader से InputStreamReader.read(char[], int, int) पर कॉल करके बड़े हिस्से में InputStreamReader से वर्णों का अनुरोध करता है, जो बदले में StreamDecoder के माध्यम से InputStream.read(byte[], int, int) पर अंतर्निहित InputStream से बाइट्स के बड़े ब्लॉक को पढ़ने के लिए कॉल करता है।

आप अपने आप को समझा सकते हैं कि यह निम्नलिखित कोड चलाकर तो है:

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 

आप निम्न उत्पादन देखेंगे:

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

यह दर्शाता है कि BufferedReader अनुरोध पात्रों में से एक बड़ी हिस्सा InputStreamReader से, जो बदले में अंतर्निहित InputStream से बाइट्स का एक बड़ा हिस्सा अनुरोध करता है।

+0

और यदि आप 'BufferedInputStream' का उपयोग करते हैं तो यह बड़े इनपुट में' इनपुटस्ट्रीम 'से डेटा का अनुरोध करता है, और इसके पाठक के' पाठकों 'के छोटे अनुरोधों को पूरक करता है। यह 'अनावश्यक' नहीं है। – EJP

+0

@EJP: मेरे उदाहरण स्निपेट में 'BufferedInputStream'' (मेरे उत्तर में पहला कोड ब्लॉक) अनिवार्य है क्योंकि 'BufferedReader'' इनपुटस्ट्रीम रीडर 'से बड़े ब्लॉक का अनुरोध करता है, जो बदले में अंतर्निहित' इनपुटस्ट्रीम 'से बड़े ब्लॉक का अनुरोध करता है। 'इनपुटस्ट्रीम रीडर' और अंतर्निहित 'इनपुटस्ट्रीम' के बीच 'बुफर्डइनपूटस्ट्रीम' का सम्मिलन केवल प्रदर्शन प्रदर्शन के बिना ओवरहेड जोड़ता है। –

1

FWIW, यदि आप जावा 8 में फ़ाइल फ़ाइल खोल रहे हैं, तो आप Files.newBufferedReader(Path) का उपयोग कर सकते हैं। मुझे नहीं पता कि प्रदर्शन यहां वर्णित अन्य समाधानों की तुलना कैसे करता है, लेकिन कम से कम यह जेडीके में बफर करने के लिए क्या निर्माण करता है, इस निर्णय को धक्का देता है।