Java IO流常用字節(jié)字符流原理解析
Java的流體系十分龐大,我們來看看體系圖:
這么龐大的體系里面,常用的就那么幾個,我們把它們抽取出來,如下圖:
一:字節(jié)流
1:字節(jié)輸入流
字節(jié)輸入流的抽象基類是InputStream,常用的子類是 FileInputStream和BufferedInputStream。
1)FileInputStream
文件字節(jié)輸入流:一切文件在系統(tǒng)中都是以字節(jié)的形式保存的,無論你是文檔文件、視頻文件、音頻文件...,需要讀取這些文件都可以用FileInputStream去讀取其保存在存儲介質(zhì)(磁盤等)上的字節(jié)序列。
FileInputStream在創(chuàng)建時通過把文件名作為構(gòu)造參數(shù)連接到該文件的字節(jié)內(nèi)容,建立起字節(jié)流傳輸通道。
然后通過 read()、read(byte[])、read(byte[],int begin,int len) 三種方法從字節(jié)流中讀取 一個字節(jié)、一組字節(jié)。
2)BufferedInputStream
帶緩沖的字節(jié)輸入流:上面我們知道文件字節(jié)輸入流的讀取時,是直接同字節(jié)流中讀取的。由于字節(jié)流是與硬件(存儲介質(zhì))進行的讀取,所以速度較慢。而CPU需要使用數(shù)據(jù)時通過read()、read(byte[])讀取數(shù)據(jù)時就要受到硬件IO的慢速度限制。我們又知道,CPU與內(nèi)存發(fā)生的讀寫速度比硬件IO快10倍不止,所以優(yōu)化讀寫的思路就有了:在內(nèi)存中建立緩存區(qū),先把存儲介質(zhì)中的字節(jié)讀取到緩存區(qū)中。CPU需要數(shù)據(jù)時直接從緩沖區(qū)讀就行了,緩沖區(qū)要足夠大,在被讀完后又觸發(fā)fill()函數(shù)自動從存儲介質(zhì)的文件字節(jié)內(nèi)容中讀取字節(jié)存儲到緩沖區(qū)數(shù)組。
BufferedInputStream 內(nèi)部有一個緩沖區(qū),默認大小為8M,每次調(diào)用read方法的時候,它首先嘗試從緩沖區(qū)里讀取數(shù)據(jù),若讀取失?。ň彌_區(qū)無可讀數(shù)據(jù)),則選擇從物理數(shù)據(jù)源 (譬如文件)讀取新數(shù)據(jù)(這里會嘗試盡可能讀取多的字節(jié))放入到緩沖區(qū)中,最后再將緩沖區(qū)中的內(nèi)容返回給用戶.由于從緩沖區(qū)里讀取數(shù)據(jù)遠比直接從存儲介質(zhì)讀取速度快,所以BufferedInputStream的效率很高。
public class OutputStreamWriter extends Writer { // 流編碼類,所有操作都交給它完成。 private final StreamEncoder se; // 創(chuàng)建使用指定字符的OutputStreamWriter。 public OutputStreamWriter(OutputStream out, String charsetName) throws UnsupportedEncodingException { super(out); if (charsetName == null) throw new NullPointerException("charsetName"); se = StreamEncoder.forOutputStreamWriter(out, this, charsetName); } // 創(chuàng)建使用默認字符的OutputStreamWriter。 public OutputStreamWriter(OutputStream out) { super(out); try { se = StreamEncoder.forOutputStreamWriter(out, this, (String)null); } catch (UnsupportedEncodingException e) { throw new Error(e); } } // 創(chuàng)建使用指定字符集的OutputStreamWriter。 public OutputStreamWriter(OutputStream out, Charset cs) { super(out); if (cs == null) throw new NullPointerException("charset"); se = StreamEncoder.forOutputStreamWriter(out, this, cs); } // 創(chuàng)建使用指定字符集編碼器的OutputStreamWriter。 public OutputStreamWriter(OutputStream out, CharsetEncoder enc) { super(out); if (enc == null) throw new NullPointerException("charset encoder"); se = StreamEncoder.forOutputStreamWriter(out, this, enc); } // 返回該流使用的字符編碼名。如果流已經(jīng)關(guān)閉,則此方法可能返回 null。 public String getEncoding() { return se.getEncoding(); } // 刷新輸出緩沖區(qū)到底層字節(jié)流,而不刷新字節(jié)流本身。該方法可以被PrintStream調(diào)用。 void flushBuffer() throws IOException { se.flushBuffer(); } // 寫入單個字符 public void write(int c) throws IOException { se.write(c); } // 寫入字符數(shù)組的一部分 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); } // 刷新該流??梢园l(fā)現(xiàn),刷新緩沖區(qū)其實是通過流編碼類的flush()實現(xiàn)的,故可以看出,緩沖區(qū)是流編碼類自帶的而不是OutputStreamWriter實現(xiàn)的。 public void flush() throws IOException { se.flush(); } // 關(guān)閉該流。 public void close() throws IOException { se.close(); } }
每次調(diào)用 write() 方法都會導致在給定字符(或字符集)上調(diào)用編碼轉(zhuǎn)換器。在寫入底層輸出流之前,得到的這些字節(jié)將在緩沖區(qū)中累積(傳遞給 write() 方法的字符沒有緩沖,輸出數(shù)組才有緩沖)。為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中,以避免頻繁調(diào)用轉(zhuǎn)換器。
2)BufferedWriter
帶緩沖的字符輸出流:與OutputStreamWriter的緩沖不同,BufferedWriter的緩沖是真正由自己創(chuàng)建的緩沖數(shù)組來實現(xiàn)的。故此:不需要頻繁調(diào)用編碼轉(zhuǎn)換器進行緩沖,而且,它可以提供單個字符、數(shù)組和字符串的緩沖(編碼轉(zhuǎn)換器只能緩沖字符數(shù)組和字符串)。
BufferedWriter可以在創(chuàng)建時把一個OutputStreamWriter進行包裝,為輸出流建立緩沖;
然后,通過
void write(char[] cbuf, int off, int len)
寫入字符數(shù)組的某一部分。
void write(int c)
寫入單個字符。
void write(String s, int off, int len)
寫入字符串的某一部分。
向緩沖區(qū)寫入數(shù)據(jù)。
還可以通過
void newLine()
寫入一個行分隔符。
最后,可以手動控制緩沖區(qū)的數(shù)據(jù)刷新:
void flush() 刷新該流的緩沖。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis的坑-integer類型為0的數(shù)據(jù)if?test失效問題
這篇文章主要介紹了mybatis的坑-integer類型為0的數(shù)據(jù)if?test失效問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01SpringBoot獲取前臺參數(shù)的六種方式以及統(tǒng)一響應(yīng)
本文主要介紹了SpringBoot獲取前臺參數(shù)的六種方式以及統(tǒng)一響應(yīng),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼
這篇文章主要介紹了Java使用選擇排序法對數(shù)組排序?qū)崿F(xiàn)代碼,需要的朋友可以參考下2014-02-02spring中ApplicationListener的使用小結(jié)
ApplicationListener是spring提供的一個監(jiān)聽器,本文主要介紹了spring中ApplicationListener的使用小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-07-07使用Java和SpringBoot實現(xiàn)服務(wù)器發(fā)送事件(Server-Sent Events)
使用Java開發(fā)web應(yīng)用,大多數(shù)時候我們提供的接口返回數(shù)據(jù)都是一次性完整返回,有些時候,我們也需要提供流式接口持續(xù)寫出數(shù)據(jù),以下提供一種簡單的方式,本文給大家介紹了如何在Java web中實現(xiàn)服務(wù)器發(fā)送事件,需要的朋友可以參考下2024-02-02Java實現(xiàn)數(shù)據(jù)庫連接池的方法
這篇文章主要介紹了Java實現(xiàn)數(shù)據(jù)庫連接池的方法,涉及java數(shù)據(jù)庫連接池的創(chuàng)建、連接、刷新、關(guān)閉及狀態(tài)獲取的常用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07