IO流 數據流; 設備包括硬盤和內存;
Java對數據的操作是通過流的方式;
處理數據流的對象都在IO包中;
流按操作數據分爲兩種:字節流與字符流;
按流向分爲輸入流和輸出流;
早期IO包裏出現的都是字節流,無論什麼數據都是體現爲字節形式即二進制的,稱爲字節流;字節流可以把所有的數據都可以搞定;但有一個數據是文本數據是比較常見的,爲了方便處理,單獨分爲字符流;
GBK碼錶;ASCII碼
國際標準化組織,
國際標準碼錶unicode表;這個表裏,無論什麼字符都用兩個字節表示;utf-8碼錶等;
unicode的所有字符都用兩個字節表示;16個二進制位;utf-8對unicode進行了優化;
字符流的出現可以在內部融合各種編碼表;可以自定義指定編碼表進行解析,避免使用字節流時出現碼錶不正確而成亂碼,這樣在處理文字字符時就變得方便;其他的數據都用字節流解決;
字符流繼字節流;
IO流的常用基類(2個兩類): 數據處理就兩動作,讀和寫;
字節流的抽象基類:InPutStream(讀),OutPutStream(寫)
(記憶,短的讀read,長的寫write)
字符流的抽象積累:Reader,Writer
這四個基類都是抽象的,需要被子類分別實現;
IO流其實就是圍繞讀寫去展開的;
一、字符流
(一)Writer;
protected 修飾構造方法,說明是給子類使用的,只有子類才能使用該方法;
學習體系的方法是,先看頂層,用底層
根據基類Writer的方法中append()方法可以得知,該方法底層數據操作應該是使用的StringBuilder或者StringBuffer,因爲他們方法一樣,而Writer就是調用的這兩個類的方法,其實這也可以理解得明白,StringBuilder類本來就是描述字符串緩衝區的,所以用在這裏再適合不過了;
既然IO流是用於操作數據的,那麼數據的最常見的體現形式就是文件;
那麼先以操作文件爲主來演示;
1、需求:在硬盤上,創建文件,並寫入一些文字數據;即操作數據;
找到一個子類後,只需要看構造方法就可以了,因爲他的方法父類裏都有了;
找到一個專門用於操作文件的Writer子類對象,FileWriter,後綴名爲父類名,前綴名是該流對象的功能;
繼承關係是Writer——OutputStreamWriter——FileWriter
該FileWriter流對象一被初始化,就必須要有被操作文件存在可以進行寫入操作,所以這個文件裏沒有空參構造方法;
寫入步驟:
File Writer = new FileWriter(地址文件名);
(1)創建一個FileWriter對象,該對象一被初始化就必須要明確被操作的文件;
而且該文件會被創建到指定目錄下,如果該目錄下已有同名文件,將被覆蓋;
new這個對象的目的就是在明確數據要存放的目的地;
一個完整的文件名,必須包含三部分,地址+標題+格式;不寫地址就是默認當前路徑;
注意,新建FileWriter會拋出IO異常;
(2)調用Write方法,是將字符串寫入到流中,並沒有直接寫到目的地文件中;
(3)flush()方法;
可以通過刷新流當中的緩衝數據,將緩衝中的數據直接清空一次,然後把其刷到目的文件中;
(4)close()方法,關閉流資源,但是關閉之前會刷新一次內部的緩衝中的數據,將數據刷到目的地中,和flush的區別是,flush刷新後,流可以繼續使用,close刷新後,會將流直接關閉,而不能在往內寫入了,否則會報錯;
其實,Java是不能寫數據的,因爲不同操作系統寫入操作是不一樣的,這個寫入操作不是java自身在寫入,而是調用的底層操作系統的流資源在進行寫入;所以最後一定要有一個動作就是,關閉底層資源的調用動作以釋放資源;
在IO體系上 IO異常是最常見的異常,一定要做處理動作;很多動作方法都有異常發生;
其實FileWriter構造函數中的是調用的操作系統底層的創建文件的方式創建了一個文件;
包括該類的所有的方法都是調用的底層操作系統的相關操作進行的;因爲Java是沒有這個能力的,它還要跨平臺,所以只能夠調用底層的操作來做;
2、IO異常的處理方式:throws肯定是不合適的;
凡是和設備上的數據發生關係和處理的,都會throw IO異常,無論讀寫和創建,因爲都是調用底層資源來進行操作的;
寫入數據都是寫入到流裏面了;流裏面有內部緩衝;
(流裏面的是有緩衝的,是基於字節流的;)
對於IO流的處理應該是直接拋RuntimeException(“異常描述”);
finally,一般的操作一般都是關閉資源,解鎖等一定要被執行的應用;因此流的關閉操作放在finally塊當中;
目錄分隔符要注意寫兩個,因爲是轉義字符;
finally裏面一定要對於if(fw!=null)的流進行關閉;要分別去關;不要搞與符號;
一個單獨代碼塊的元素,其作用域只能是在本代碼塊當中,不能在別的代碼塊當中訪問;
可以在外面建立引用filewrite fw=null;,這樣在最後發finally塊當中才能被訪問得了fw聲明,在代碼塊當中賦值即可;
3、對已有文件內容的數據進行續寫:
傳遞true參數,代表不覆蓋已有文件,並在已有文件的末尾處進行數據處理,
如果文件不存在就創建,存在就不創建了;(如果輸入false是不是在開頭寫入?)
FileWriter(String fileName, boolean append)
創建一個true參數,代表不覆蓋已有的文件,並在已有文件的末尾處進行屬性數據續寫;
4、在window時 \n 和\r一起才表示換行,如果文本中不顯示,會顯示一個黑塊;先r再n;
只有lincx\n才表示換行;\r表示回車,\n表示換行;只有這兩個才表示成功換行;
(二)、Reader
Reader 也是抽象類;
這個類裏面的close()不刷新;雖不刷新,但也要關閉;
讀不用刷新,寫的時候是需要刷新的,因爲寫要把流裏面的東西保存下來;
流對象有一個特點就是基本都是對應的,有讀的就肯定有寫的;但不是全都這樣;
流是已經把內容直接讀出來了,所以不需要刷新,而寫是要刷新的,因爲他要寫進去,然後還要按編碼轉換,中間肯定有一個緩衝的過程;
字符流是百分百都是有編碼的;
步驟
(1)創建一個文件讀取流對象,和指定名稱的文件相關聯,要保證該文件已經存在的,如果不存在,會發生異常 FileNotFoundException;
(2)調用讀取流對象的read方法;
方法read();一次讀一個字符,而且會自動往下讀;當讀到沒有內容時,就返回-1;
Java在讀文件的時候也是調用底層操作系統中的讀取文件的方法來讀文件內容的,Java本身是讀不了的文件的;
在硬盤上,每一個數據文件讀完之後,後面都有一個結束的標示;
(3)read(char[] cbuf) 通過字符數組進行讀取;返回讀取字符個數;
就要先定義一個字符數組,用於存儲讀到的字符;該read(char[])返回的是讀到的字符個數;
(4)關閉資源,雖然不影響讀取,但是關閉動作一定要有;
注意,IO流實際是調取了底層操作系統來完成數據操作處理的,讀有一個特點就是隻要沒有關閉流,它讀到哪裏就停到哪裏,下次不會從開頭重新開始;其實硬盤就是磁頭在讀寫,所以讀到哪裏就停到哪裏了;
用數組讀其實有一個特點就是他是用讀入流當中的內容覆蓋數組中原有的內容;
每一次read()都是從數組的0腳標開始讀起,就和重複讀一樣,但是如果數組裝滿,就會停止讀入;
如果數組的空間裝滿,則read動作將停止,表示該read語句執行結束,磁頭停止在所讀的最後一個字符的後面,直到關閉該流;
一般的通常情況下,數組的長度定位1024的整數倍;1024字節就是1kb,一個字符是兩個字節;
用數組先緩衝一下,然後再讀出來;比讀一個打一個的更快捷方便;
練習:讀取一個java文件,並打印在控制檯上;
字符流,專門處理文本數據的對象;
注意,如果你的文檔裏面自己有換行,那麼打印的時候他肯定也是打印換行的,因爲有一個換行符在那裏,所以連續打印最好;
練習2:將c盤的一個文本文件複製到d盤。
複製原理,其實就是將c盤下的文件數據存儲到d盤的一個文件中,
步驟:
在d盤創建一個文件,用於存儲c盤文件中的數據;
定義讀取流和c盤文件關聯;
通過不斷的讀寫完成數據存儲,
關閉資源;
兩種方法;第一種讀一個寫一個,第二種,數組;
讀寫操作都進入流對象了;
複製動作要做重點掌握;
流對象的概念;其實流的底層都是調用的windows的底層資源的;
第二種方式:用數組臨時存一下,提高讀寫性能;
局部變量定義時,最好養成一個習慣就是初始化一下,因爲沒賦值前就不能調用的;
把讀到的內容寫到流裏面去,即流的緩衝區中;
字符流體系當中的緩衝技術;
讀寫失敗之後,專業異常的處理動作應該是throwRuntimeException(“讀寫失敗”)
讀寫完畢後,在finally塊中,關閉兩個流資源;
(三)字符流的緩衝區:
如何提高程序的讀寫效率呢?
水滴石穿坐食山空
其實很多軟件裏面都加入了自己的緩衝技術;先存在一個內存當中,讀到一定內容後,再一次性寫入到硬盤中;這樣讀寫性能比較就會好些,磁頭沒有必要來回切換,提高讀寫速度;
緩衝區的出現提高了對數據的讀寫效率;
爲提高讀寫效率,字符流也提供了相對應的緩衝區對象
具備緩衝技術的字符流對應的有BufferedWriter和BufferReader;緩衝區要結合流纔可以使用;在流的基礎上對流的功能進行了增強;
具備緩衝技術的字符流;
1、BufferedWriter
將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。
(磁頭沒有必要來回切換),這個緩衝區就是在比較方便的地方存入;比直接在目的文件裏讀入寫出會性能更高,具體爲什麼,再研究;只知道,緩衝區是在內存裏,比直接放在硬盤中讀寫速度會更快;
緩衝區是爲了提高流的讀寫效率而出現,因此在創建緩衝區之前就應該先有流對象;即初始化創造對象時就要先有流對象,故沒有空參的構造函數,就像蓄水池一樣,建立之前必須要有水才流行;
步驟:
(1)創建一個字符寫入流對象;
一般開發時都要開緩衝區,這樣對性能就會有所提高;
(2)爲了提高字符寫入流效率,加入了緩衝技術,只要將需要被提高效率的流對象作爲參數傳遞給緩衝對象的構造函數即可;(其實緩衝區最根本原理就是底層原理就是加了一個數組;)
把緩衝區與流對象相關聯後就可以直接用緩衝區的操作方法了;而不再用流對象去操作了;
注意,只要用到緩衝區,就要記得刷新;flush();//字節流不需要刷新;
緩衝區的存在是爲了提高效率的,而這個緩衝區的底層調用的就是對應的流對象在進行操作,其實操作緩衝區就在操作的流對象,只是定義了一些更多更好的方法在裏面,所以關閉緩衝區其實就是在關閉流對象;這點從它的繼承體系中就可以看到,他是繼承Writer類的;
其實關閉緩衝區就是在關閉緩衝區中的流對象;所以不用在關閉流對象;緩衝區本是不存在關閉的;
緩衝區是在內存裏面;一停電就肯定釋放內存了;,所以爲了安全可見,可以邊寫邊刷;
該緩衝區當中,提供了跨平臺的添加換行符newline()方法;
2、BufferedReader
從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。
讀取流在建立對象時,也要有一個被緩衝的對象;故有一個含參的構造函數;
FileReader對象在讀取的時候每次都是一個一個讀的,所以比較低效;
(1)創建一個讀取流對象和文件相關聯;
(2)爲了提高效率,加入緩衝技術,將字符讀取流對象作爲參數傳遞給緩衝對象的構造函數。
(3)關閉緩衝流對象;
該緩衝區提供了一個一次讀一行的方法readline();,方便於對文本數據的獲取,當返回null時,讀到文件的末尾;把這個作爲循環的條件;String默認值爲null;
文本都是一行一行存在的;
readline方法返回的字符串內容中不包含任何的行終止符;
練習:通過緩衝區複製一個java文件;
在建立緩衝區流對象後,完成所有的流操作後,都要對緩衝區流對象進行關閉,這樣就釋放了流對象佔的內存空間;
其實對緩衝的流對象操作後,其中就把對目的文件的流操作封裝在裏面了,直接關閉這個流對象就把所有的流對象都關閉了。
注意readline方法返回的時候只返回回車符之前的數據內容,並不返回回車符;
兩個流之間是需要中轉站才能進行復制的;
3、readline方法的原理: 模擬緩衝區的原理;
無論是讀一行,或者讀取多個字符,其實最終都是在硬盤上一個一個讀取,所以最終使用的還是read方法即一次讀一個的方法;其底層是用的數組結構來乾的;
所謂緩衝區的好處就是讀的數據沒有直接操作,而是先存下來,讀到一定數量後就一起操作;這樣就會相對高效很多;
練習:
明白了BufferedReader類中的特有方法readline的原理後,可以自定義一個類中包含一個功能和readline一致的方法;來模擬一下BufferedReader;可以讀一行數據的方法;
臨時容器可以用Stringbuilder來處理,因爲長度沒有限制並且最終還是打印成字符串;比定義數組方便;
因爲不明確到底要多少個數據,所以用StringBuilder比較靈活;
像流當中,StringBuilder類應該是比較好用的一個類,因爲他比數組靈活,而且最終也返回的是字符串;
定義功能工具類的時候,裏面的會拋出異常的操作直接throws,讓調用者去try;
4、裝飾設計模式;用於類的功能加強;
readline方法其實就是在增強了讀入的功能;
增強功能,將被增強的對象傳給增強的類;
這種設計模式我們稱爲裝飾設計模式;
裝飾設計模式,是指當想要對已有的對象進行功能增強時,可以定義加強的類,將已有對象傳入,基於已有對象的功能,並提供加強功能;
那麼自定義的該類,就稱爲裝飾類;
模式都是基於原有的東西不斷優化出來的;
後期進行功能擴展增強時,不建議改源代碼,改源代碼是災難,所以可以按這種模式類進行功能擴展;
該裝飾設計模式可以用於功能擴展的應用,可以跟接口搶飯吃;
裝飾完後一般都是同屬於一個接口或者類,是同一個體系中的成員;
裝飾類通常會通過構造方法接收被裝飾對象,並基於被裝對象的功能,提供更強的功能;
super.method(); 繼承父類後,使用父類的方法;
裝飾模式的設計方式:構造函數傳遞,進行功能增強;
裝飾模式和繼承的關係;
提高效率可以用緩衝技術;
裝飾設計模式,將原子類的一一繼承體系進行了優化後而產生的體系,而且擴展性比之前的也強很多;
裝飾模式比繼承要靈活,避免了繼承的臃腫,擴展性也好了很多,而且降低了類與類之間的關係;
注意:裝飾類因爲增強已有對象,具備動能和已有的是相同的,只不過提供了更強功能,所以裝飾類和被裝飾類通常是都屬於一個體系中;
從繼承結構變成了組合結構;
繼承要寫,但是不要寫得太多,可以通過裝飾的功能來擴展已知類的功能,否則,繼承的體系將會變得非常的複雜;裝飾模型靈活性比繼承更強;體系也變得更加簡單;
裝飾類的對象可以把構造函數的參數類變爲父類,使用也更廣,更靈活;
把每一個具體子類的繼承變成了基類的繼承,通過傳入子類的對象來加強這一個大家族的功能;使體系更簡單,擴展性也更強;這就是裝飾類;
在實際開發中進行功能擴展時非常的適用;想進行升級的時候來一個裝飾類繼承一下基類進行功能增強,如果做的不好,再繼續用你原來的即可;
一般地,裝飾類基本都繼承了基類,這樣才能給更多子類加強,如果不是給更多子類加強只需要繼承被裝飾類即可;
繼承基類時,要注意覆蓋基類當中的抽象方法;因爲抽象的類無法實例化;
繼承,調用父類方法就用super,不繼承就用對象調用都一樣;
發現繼承可以用直接把父類的對象傳入構造函數替代,如果用繼承,裏面的方法直接super點方法即可,調用的時候只new一個子類的對象即可,如果不用繼承,就必須還要new一個父類對象,同時new子類對象,把父類傳入子類構造函數;
5、LineNumberReader類是BufferedReader的子類;
BufferedReader,功能增強的緩衝區;
LineNumberReader類也是一個包裝類或者說裝飾類;
先要有一個被包裝的流對象;
跟蹤行號的緩衝字符輸入流。此類定義了方法 setLineNumber(int) 和 getLineNumber(),它們可分別用於設置和獲取當前行號。
流對文件讀取的時候讀一行加一個行號;
該類就是自定義了一個私有的行號屬性而已;別無其他;
練習:模擬一個帶行號的緩衝區的對象;
LineNumberReader的原理:讀的時候加了一個計數器;
都是裝飾類
---------------------------------------------------------------------------------------------------------------------------------
總結:
字符流中學到的幾個重要的對象:
FileReader//FileWriter//BufferedReader//BufferedWriter
二、字節流:
操作的數據都是字節數據,其實字符流也是字節數據,只是它裏面有默認碼錶在自動轉換;
1、需求:想要操作圖片數據,這時就要用到字節流;
圖片是一文件,所以就要找到字節流體系當中能操作文件的對象;
InPutStream (短read讀)OutPutString(長write寫)
注意:字符流使用的是字符數組,字節流使用的是字節數組;
學習API的方法就是,找到抽象類之後,學到方法後,直接找一個子類用一下就搞定了,
流對象一創建,就馬上在內存建立了一個文件的;
同樣,流對象都是要拋異常的;
字符流其實也走的是字節,只是他要先在臨時存儲存入起來,比如一箇中文兩個字節,讀一個字節不能立即操作,字符流底層也是用的字節流的緩衝區,字符緩衝區有一個數組是用來臨時存儲數據的,所以字符流需要一個刷新動作,如果直接使用字節流操作沒有使用具體指定的緩衝區,是不需緩衝的,不管什麼類型數據,都可以以字節來直接操作寫入到目的文件中區,所以不需要刷新的,只有有緩衝纔要刷新,字節流因爲對字節最小單位操作,直接往目的地操作就行了,中間不需要做任何的轉換,故不需要緩衝操作,因此也不需要刷新直接就可以寫入文件;
但是close要寫,因爲調用的底層資源要關閉掉;
第19-11視頻中打印成new String (buf,0,len);有些不是很瞭解,爲什麼要這麼做,要轉成字符串?哦 這個好像也是字符串的一種表達而已,直接表達不行麼? 好像不行;試一下;
這個是把數組變成string;—————
—————————第二次看視頻 看到了這個筆記——笑了一下————哈哈…………典型的看了後面的忘記前面的;.…………………………………………………………
FileInputStream中的方法
int available() 返回文件中的字節數;
可以用來定義讀數據時建立數組時的定義的個數;
定義剛好的元素個數的數組就不需要循環了;
但是不能夠用來定義讀取超大文件的的數組的元素個數;
字節流可以操作很多的媒體元素;
虛擬機啓動時,默認的內存空間是64m的。
如果處理的文件太大,就會出現內存溢出,這時候available()方法裝不了這麼大的文件,所以在定義數組的長度時用available方法時要慎重,還是以1024的整數倍比較好;因爲是要new一個數組出來,內存開闢不了這麼大的空間給你;因爲後面的是,如果裝不下,就直接打印,然後再重新讀;
2、練習,拷貝圖片
圖片屬於媒體文件;
思路:
(1)用字節讀取流對象和圖片關聯;
(2)用字節寫入流對象創建一個圖片文件,用於存儲獲取到的圖片數據;
(3)通過循環讀寫,完成數據的存儲;
(4)關閉資源;
用字符流拷貝媒體文件的時候,如果有編碼表不認識的代碼就會就會變成默認替代不識別區的代碼,這時裏面的字節碼就變化了;因爲他已經通過編碼表把碼給改了,所以複製的媒體文件就看不了;
字節流的緩衝區演示:通過MP3的複製;BufferedOutputStream,BufferedInputStream
緩衝區是爲了提高效率而出現的;
緩衝區裏面是已經封裝了數組的,所以就不需要再寫數組了,他們都在內部操作;
模版方法設計來定義獲取時間;System.currentTimeMillis();
3、自定義字節流緩衝區;
自定義字節流緩衝區來提高流的讀寫速度;
因爲StringBuilder都會自動變成字符串,所以爲了保證源碼,自定義就用數組;
數組裏面會有隱式的指針在指導操作;
這個代碼的原理沒有弄太明白
類 BufferedOutputStream 該類實現緩衝的輸出流。通過設置這種輸出流,應用程序就可以將各個字節寫入底層輸出流中,而不必針對每次字節寫入調用底層系統。
read(byte[] b 數組操作的返回值是次數;
讀入緩衝區的字節總數,如果因爲已經到達文件末尾而沒有更多的數據,則返回 -1。
MP3裏面的數據都是二進制數據;
小問題是因爲mp3前面讀到了8個1所以讀成了-1,而造成無法複製;
outputsream中的Write方法總是在寫最低的八個字節;不寫其他類型;只寫一個字節;write方法在寫的時候總會強行向下強轉爲byte型的字節;
爲什麼read()方法一定要返回int而不是返回byte呢?
因爲如果遇到-1的情形,byte無法處理,從而使得數據不安全,而返回int後可以&255,這樣就可以避免非-1而變成了-1給返回了,而在write的時候再自動都轉爲byte寫入就可以了;與上255後,就不會有負數出現了;write自動取int的最後八位就還原了;在byte範圍內的數與上255後的數結果都沒有變,只有負數纔會變,正數都不會變;但是負數都是變成正數了,但其最後八位還是沒有變;而write執行的時候,就只取最後八位;
———————————————————————————————————————
總結
字節流:FileInputStream FileOutputStream BufferedInputStream BufferedOutputStream
三、讀取鍵盤錄入
鍵盤錄入的形式獲取數據;
System.out :對應的是標準輸出設備;對應的是控制檯;
System.in: 對應的標準的輸入設備;對應是鍵盤;
只要操作數據都要用到流對象;
InPutStream 字節讀取流對象;
老師說這時候知道爲什麼read方法是int了 搞得我自以爲懂了,這句話讓我又迷惑了;
這裏的read方法是阻塞式方法;如果沒有輸入沒有讀到數據就會停止等待;
需求:通過鍵盤錄入數據,當錄入一行數據後,就將改行數據進行打印,如果錄入的數據是over,那麼停止錄入;
ctrl+c 其實返回的就是-1,輸入是輸入不進去的;
鍵盤錄入的時候可以不用close,因爲是系統錄入,所以停止了就自動關閉了;
通過鍵盤錄入一行數據並打印其大寫,發現其實就是讀一行數據的原理,也就是readline方法;能不能直接使用readline方法來完成鍵盤錄入的一行數據的讀取呢?
readline方法是字符流BufferedReader類的方法,而鍵盤錄入的read方法是字節流InPutStream的方法。
那麼能不能將字節流轉成字符流在使用字符流緩衝區的readline的方法呢?
步驟:
(1)獲取鍵盤錄入的對象;
(2)將字節流對象轉換爲字符流對象,使用轉換流InputStreamReader
(3)爲了提高效率,用緩衝流對象;
四、轉換流對象;
InputStreamReader 專門用於操作字節流的字符流對象;InputStreamReader是字節流通向字符流的橋樑:
把鍵盤錄入用readline方法來編寫,採取InputStreamReader的方法;
如果把打印語句放在循環外面會有什麼效果呢?
OutputStreamWriter 字符轉字節流 錄入字符,轉成字節存取在硬盤上;
因爲最終只有鍵盤錄入的流在操作,所以用轉換流之後,流對象關不關都可以;手上停止操作就關閉了;
鍵盤錄入要麼ctrl+C,要麼自定義結束標記;
輸出語句底層就是用的流對象;
鍵盤錄入最常見寫法:
BufferedReader bufr = new BufferedReader(newInputStreamReader(System.in))
String line = null;
while((line =bufr.readLine())!=null){
if(“over”.equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close;
1、源:鍵盤輸入;目的:控制檯;
2、需求:把鍵盤錄入的數據存儲到一個文件中;
源 鍵盤 目的:文件
3、需求:想要將一個文件的數據打印在控制檯上;
源:文件,目的,控制檯;
流操作的基本規律:
最痛苦的就是流對象有很多,不知道該用哪一個?
通過三個明確來完成;
1、明確源和目的;
源:輸入流:InPutStream,Reader;
目的:輸出流:outputstream;Writer;
2、明確操作的數據是否是純文本;
是:字符流;不是:字節流;
3、當體系明確後,再明確要使用哪個具體的流對象;
通過設備來進行區分;
源設備:內存,硬盤,鍵盤
目的設備:內存;硬盤,控制檯;
1、將一個文本文件中的數據存儲在另一個文件中,即複製文件;
源:因爲是源,所以使用讀取流,InPutStream 或Reader
是不是操作文本文件,是,這是就可以選擇Reader;
這樣體系就明確了;
接下來,明天要使用的該體系中的哪個對象?
明確設備:硬盤,一個文件;
Reader體系中可以操作文件的對象是FileReader
是否需要提高效率:是,加入Reader體系中的緩衝區 BufferedReader;
FileReader fr = new FileReader(“a.txt”);
BufferedReader bufr = new BufferedReader;
目的:OutPutStream 或者Writer;
是否是純文本;是,使用Writer;
設備:硬盤,一個文件;
Writer體系中可以操作文件的對象爲FileWrite;
FileWrite fw = new FileWrite( “b。txt”);
是否需要提高效率:是,加入Writer體系中的緩衝區 BufferedWriter;
BufferedWriter bw = new BufferedWriter(fw);
練習:將一個圖片文件中的數據存儲到另一個文件中;複製文件,要按照以上格式完成三個明確;
2、需求:將鍵盤錄入的數據保存到一個文件中;
這個需求中,有源和目的都存在;那麼分別分析;
源:InPutStream或者Reader;
是不是純文本,是,Reader; 因爲鍵盤錄入不了圖片;
設備:鍵盤: 對應的對象是system.in;
而System。in對應的是字節流,怎麼選擇的是Reader呢?
爲了操作鍵盤的文本數據方便,轉成字符流按照字符串操作最方便;所以既然明確了Reader,那麼就將System。in轉換成了Reader。用了Reader體系中的轉換流,InPutStreamReader。
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率嗎?需要!BufferedReader;
BufferedReader bufr = new BufferedReader(isr);
當需求只是只需要讀取數據直接打印就可以了時,這時就沒有什麼必要再去加轉換流了,不需要字節轉字符了;
FileWrite fw = new FileWrite( “b。txt”);
是否需要提高效率:是,加入Writer體系中的緩衝區 BufferedWriter;
BufferedWriter bw = new BufferedWriter(fw);
擴展一下,想要把錄入的數據按照指定的編碼表(utf-8),將數據存入到文件中;
默認編碼表GBK;
要想指定編碼用的就是轉換流,他裏面是可以指定編碼表的;
其實進行字符轉換,其實就用的轉換流,裏面根據了指定的編碼表進行轉換的;
轉換流真正的的應用就是能夠把字節轉換過來,通過查指定的碼錶轉換;
只有轉換流才能指定編碼表;
目的:OutPutStream 或者Writer;
是否是純文本;是,使用Writer;
設備:硬盤,一個文件;
Writer體系中可以操作文件的對象爲FileWrite;
但是FileWriter使用的是默認編碼表GBK;
但是存儲時,需要加入指定編碼表UTF-8,而指定的編碼表只有轉換流可以指定;
所以要使用的對象是OutPutStreamWriter,
而該轉換流對象要接受一個字節輸出流,而且還可以操作的文件的字節輸出流,fileoutputstream;
OutPutStreamWriter osw = newOutPutStreamWriter(new FileOutPutString(“d.txt”),“UTF-8”)
需要高效嗎?需要
BufferedWriter bw = new BufferedWriter(osw);
轉換流什麼時候使用呢?字符和字節之間的橋樑,通常涉及到字符編碼轉換時,需要用到轉換流;
練習:將一個文本數據打印在控制檯上,要按照以上格式完成三個明確。
改變標準輸入的設備和輸出設備;System.setOut(); System.setIn();
log4j工具很方便,是專門幫助我們建立java日誌信息;
打印系統信息;
目的的改變,流就是用來操作數據的;數據都已經封裝成數據了;
總結:
1、其實流裏面所有的功能就是解決這幾種需求,其中每一種需求的方法模型和操作都是一模一樣的;關鍵要理解流的對象的概念,以及每一個流操作的底層原理;
鍵盤錄入——控制檯;
鍵盤錄入——文件;
文件——控制檯;
文件——文件;
文件—內存—控制檯;
2、裝飾設計模式的加入,使得將功能進行了一些加強並進行了封裝,提高了效率,成爲裝飾模式;在流這塊知識點中,就是Buffered——,四種緩衝流對象;NumLineReader;