JavaIO流原理之經常使用字節流和字符流詳解以及Buffered高效的原理

轉載請註明原文地址:http://www.cnblogs.com/ygj0930/p/5827509.html html

    Java的流體系十分龐大,咱們來看看體系圖:
 
     這麼龐大的體系裏面,經常使用的就那麼幾個,咱們把它們抽取出來,以下圖:
 
    一:字節流
        1:字節輸入流
           字節輸入流的 抽象基類是InputStream,經常使用的子類是 FileInputStream和BufferedInputStream。
           1)FileInputStream
           文件字節輸入流:一切文件在系統中都是以 字節的形式保存的,不管你是文檔文件、視頻文件、音頻文件...,須要讀取這些文件均可以用FileInputStream去讀取其保存在存儲介質(磁盤等)上的字節序列。
           FileInputStream在建立時經過把文件名做爲構造參數鏈接到該文件的字節內容,創建起字節流傳輸通道。
           而後經過 read()、read(byte[])、read(byte[],int begin,int len) 三種方法 從字節流中讀取 一個字節、一組字節。
           
           2)BufferedInputStream
           帶緩衝的字節輸入流:上面咱們知道文件字節輸入流的讀取時,是直接同字節流中讀取的。因爲 字節流是與硬件(存儲介質)進行的讀取,因此速度較慢。而CPU須要使用數據時經過read()、read(byte[])讀取數據時就要受到硬件IO的慢速度限制。咱們又知道, CPU與內存發生的讀寫速度比硬件IO快10倍不止,因此優化讀寫的思路就有了:在內存中創建緩存區,先把存儲介質中的字節讀取到緩存區中。CPU須要數據時直接從緩衝區讀就好了,緩衝區要足夠大,在被讀完後又觸發fill()函數自動從存儲介質的文件字節內容中讀取字節存儲到緩衝區數組。
           BufferedInputStream 內部有一個緩衝區,默認大小爲8M,每次調用read方法的時候,它首先嚐試從緩衝區裏讀取數據,若讀取失敗(緩衝區無可讀數據),則選擇從物理數據源 (譬如文件)讀取新數據(這裏會嘗試儘量讀取多的字節)放入到緩衝區中,最後再將緩衝區中的內容返回給用戶.因爲從緩衝區裏讀取數據遠比直接從存儲介質讀取速度快,因此BufferedInputStream的效率很高。
public class OutputStreamWriter extends Writer {

// 流編碼類,全部操做都交給它完成。

    private final StreamEncoder se;


// 建立使用指定字符的OutputStreamWriter。

    public OutputStreamWriter(OutputStream out, String charsetName)


            throws UnsupportedEncodingException

    {


        super(out);


        if (charsetName == null)



            throw new NullPointerException("charsetName");


        se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);

    }


// 建立使用默認字符的OutputStreamWriter。

    public OutputStreamWriter(OutputStream out) {


        super(out);


        try {



            se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);


        } catch (UnsupportedEncodingException e) {



            throw new Error(e);


        }

    }


// 建立使用指定字符集的OutputStreamWriter。

    public OutputStreamWriter(OutputStream out, Charset cs) {


        super(out);


        if (cs == null)



            throw new NullPointerException("charset");


        se = StreamEncoder.forOutputStreamWriter(out, this, cs);

    }


// 建立使用指定字符集編碼器的OutputStreamWriter。

    public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {


        super(out);


        if (enc == null)



            throw new NullPointerException("charset encoder");


        se = StreamEncoder.forOutputStreamWriter(out, this, enc);

    }


// 返回該流使用的字符編碼名。若是流已經關閉,則此方法可能返回 null。

    public String getEncoding() {


        return se.getEncoding();

    }


// 刷新輸出緩衝區到底層字節流,而不刷新字節流自己。該方法能夠被PrintStream調用。

    void flushBuffer() throws IOException {


        se.flushBuffer();

    }


// 寫入單個字符

    public void write(int c) throws IOException {


        se.write(c);

    }


// 寫入字符數組的一部分

    public void write(char cbuf[], int off, int len) throws IOException {


        se.write(cbuf, off, len);

    }


// 寫入字符串的一部分

    public void write(String str, int off, int len) throws IOException {


        se.write(str, off, len);

    }


// 刷新該流。能夠發現,刷新緩衝區實際上是經過流編碼類的flush()實現的,故能夠看出,緩衝區是流編碼類自帶的而不是OutputStreamWriter實現的。

    public void flush() throws IOException {


        se.flush();

    }


// 關閉該流。

    public void close() throws IOException {


        se.close();

    }
}

       每次調用 write() 方法都會致使在給定字符(或字符集)上調用編碼轉換器。在寫入底層輸出流以前,獲得的這些字節將在緩衝區中累積(傳遞給 write() 方法的字符沒有緩衝,輸出數組纔有緩衝)。爲了得到最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以免頻繁調用轉換器。數組

 

        2)BufferedWriter緩存

        帶緩衝的字符輸出流:與OutputStreamWriter的緩衝不一樣,BufferedWriter的緩衝是真正由本身建立的緩衝數組來實現的。故此:不須要頻繁調用編碼轉換器進行緩衝,並且,它能夠提供單個字符、數組和字符串的緩衝(編碼轉換器只能緩衝字符數組和字符串)。函數

        BufferedWriter能夠在建立時把一個OutputStreamWriter進行包裝,爲輸出流創建緩衝;優化

        而後,經過this

void write(char[] cbuf, int off, int len) 
          寫入字符數組的某一部分。 
 void write(int c) 
          寫入單個字符。 
 void write(String s, int off, int len) 
          寫入字符串的某一部分。 

       向緩衝區寫入數據。編碼

       還能夠經過spa

 void newLine() 

       寫入一個行分隔符。 code

       最後,能夠手動控制緩衝區的數據刷新:視頻

void flush() 刷新該流的緩衝。 
相關文章
相關標籤/搜索