IO流:用於處理設備上的數據。設計模式
設備:硬盤,內存,鍵盤錄入。數組
IO有具體的分類:app
1:根據處理的數據類型不一樣,字節流和字符流。函數
2:根據流向不一樣,輸入流和輸出流。學習
字符流的由來:優化
由於文件編碼的不一樣,而有了對字符進行高效操做的字符流對象。ui
原理:其實就是基於字節流讀取字節時,去查了指定的碼錶。this
字節流和字符流的區別:編碼
1:字節流讀取的時候,讀到一個字節就返回一個字節。設計
字符流使用了字節流讀到一個或多個字節(中文對應的字節數是兩個,在UTF-8碼錶中是3個字節)時。先去查指定的編碼表,將查到的字符返回。
2:字節流能夠處理全部類型的數據,如圖片,mp3,avi。
而字符流只能處理字符數據。
結論:只要是處理純文本數據,就要優先考慮使用字符流。除此以外都用字節流。
IO的體系。所具有的基本功能就是兩個:讀和寫。
1:字節流
InputStream(讀),OutputStream(寫)。
2:字符流
Reader(讀),Writer(寫)。
基本的讀寫操做方式:
由於數據一般都以文件形式存在。
因此就要找到IO體系中能夠用於操做文件的流對象。
經過名稱能夠更容易獲取該對象。
由於IO體系中的子類名後綴絕大部分是父類名稱。而前綴都是體現子類功能的名稱。
Reader
InputStreamReader
FileReader:專門用於處理文件的字符讀取流對象。
Writer
OutputStreamWriter
FileWriter:專門用於處理文件的字符寫入流對象。
Reader中的常見的方法:
1:int read():
讀取一個字符。返回的是讀到的那個字符。若是讀到流的末尾,返回-1.
2:int read(char[]):
將讀到的字符存入指定的數組中,返回的是讀到的字符個數,也就是往數組裏裝的元素的個數。若是讀到流的末尾,返回-1.
3:close():
讀取字符其實用的是window系統的功能,就但願使用完畢後,進行資源的釋放。
Writer 中的常見的方法:
1:write(ch):將一個字符寫入到流中。
2:write(char[]):將一個字符數組寫入到流中。
3:write(String):將一個字符串寫入到流中。
4:flush():刷新流,將流中的數據刷新到目的地中,流還存在。
5:close():關閉資源:在關閉前會先調用flush(),刷新流中的數據去目的地。而後流關閉。
FileWriter:
該類沒有特有的方法。只有本身的構造函數。
該類特色在於,
1:用於處理文本文件。
2:該類中有默認的編碼表,
3:該類中有臨時緩衝。
構造函數:在寫入流對象初始化時,必需要有一個存儲數據的目的地。
FileWriter(String filename):
該構造函數作了什麼事情呢?
1:調用系統資源。
2:在指定位置,建立一個文件。
注意:若是該文件已存在,將會被覆蓋。
FileWriter(String filename,boolean append):
該構造函數:當傳入的boolean類型值爲true時,會在指定文件末尾處進行數據的續寫。
FileReader:
1:用於讀取文本文件的流對象。
2:用於關聯文本文件。
構造函數:在讀取流對象初始化的時候,必需要指定一個讀取的文件。
若是該文件不存在會發生FileNotFoundException.
FileReader(String filename);
清單 1:
1:將文本數據存儲到一個文件中。
對於讀取或者寫入流對象的構造函數,以及讀寫方法,還有刷新關閉功能都會拋出IOException或其子類。
因此都要進行處理。或者throws拋出,或者 try catch 處理。
清單 2:
完整的異常處理方法。
清單 3:
讀取一個已有的文本文件,將文本數據打印出來。
一次讀一個字符就打印出來,效率不高。
讀一個字符就存入字符數組裏,讀完1kb 再打印。
字符流的緩衝區:
緩衝區的出現提升了對流的操做效率。
原理:其實就是將數組進行封裝。
對應的對象:
BufferedWriter:
特有方法:
newLine():跨平臺的換行符。
BufferedReader:
特有方法:
readLine():一次讀一行,到行標記時,將行標記以前的字符數據做爲字符串返回。當讀到末尾時,返回 null.
在使用緩衝區對象時,要明確,緩衝的存在是爲了加強流的功能二存在,
因此在創建緩衝區對象時,要先有流對象存在。
其實緩衝內部就是在使用流對象的方法,只不過加入了數組對數據進行了臨時存儲。爲了提升操做數據的效率。
代碼上的體現:
寫入緩衝區對象。
//創建緩衝區對象必須把流對象做爲參數傳遞給緩衝區的構造函數。
BufferedWriter bufw = new BufferedWriter(new FileWriter("buf.txt"));
bufw.write("abce");//將數據寫入到了緩衝區。
bufw.flush();//對緩衝區的數據進行刷新。將數據刷到目的地中。
bufw.close();//關閉緩衝區,其實關閉的是被包裝在內部的流對象。
讀取緩衝區對象。
BufferedReader bufr = new BufferedReader(new FileReader("buf.txt"));
String line = null;
//按照行的形式取出數據。取出的每個行數據不包含回車符。
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
練習:經過緩衝區的形式,對文本文件進行拷貝。
public static void main(String[] args) {
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
String line = null;
while((line = bufr.readLine())!= null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
readLine():方法的原理:
其實緩衝區中的該方法,用的仍是與緩衝區關聯的流對象的read 方法。
只不過,每一次讀到一個字符,先不進行具體操做,先進行臨時存儲。
當讀取到回車標識時,將臨時容器中存儲的數據一次性返回。
既然明確了原理,咱們也能夠實現一個相似功能的方法。
class MyBufferedReader {
private Reader r;
MyBufferedReader(Reader r) {
this.r = r;
}
public String myReadLine() throws IOException {
//1:建立臨時容器。
StringBuilder sb = new StringBuilder();
//2:循環的使用read方法不斷讀取字符。
int ch = 0 ;
while((ch = r.read())!=-1) {
if(ch == '\r')
continue;
if(ch == '\n')
return sb.toString
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
public void myClose() throws IOException {
r.close();
}
}
main() {
MyBufferedReader myBufr = new MyBufferedReader(new FileReader("a.txt"));
String line = null;
while((line = myBufr.myReadLine())!=null) {
System.out.println(line);
}
}
它的出現基於流並加強了流的功能。
這也是一種設計模式的體現:裝飾設計模式。
對一組對象進行功能的加強。
該模式和繼承有什麼區別呢?
它比繼承有更好的靈活性。
一般裝飾類和被裝飾類都同屬於一個父類或者接口。
Writer
--->MediaWriter
--->TextWriter
(注:MediaWriter 與 TextWtiter 兩個類在 JDK中並不存在,爲了更形象的舉例說明而「建立」的 ,不要誤解哈。)
需求:想要對數據的操做提升效率,就用到了緩衝技術。
經過所學習的繼承特性。能夠創建子類複寫父類的write方法。便可
Writer:(注:不要誤解,如下兩個對象不存在,只爲舉例。)
--->MediaWriter
--->BufferedMediaWriter
--->TextWriter
--->BufferedTextWriter
當 Writer 中子類對象過多,那麼爲了提升每個對象效率,每個對象都有一個本身的子類Buffered。
雖然能夠實現,可是繼承體系變的很臃腫。
那麼是否能夠對其進行一下優化呢?
其實子類都是在使用緩衝技術。
可不能夠對緩衝技術進行描述,將須要加強的對象傳遞給緩衝區便可。
class BufferedWriter {
BufferedWriter(MediaWriter mw) {}
BufferedWriter(TextWriter mw) {}
}
該類雖然完成了對已有兩個對象的加強。
可是當有新的對象出現時,仍是繼續在該類中添加構造函數。這樣不利於擴展和維護。
將對這些對象父類型進行操做便可。這就是多態,提升了程序的擴展性。
同時BufferedWriter 中同樣具備write方法,只不過是加強後的write。
因此BufferedWriter也應該是Writer中的一個子類。
class BufferedWriter extends Writer {
private Write w;
BufferedWriter(Writer w) {
this.w = w;
}
}
Writer
--->MediaWriter
--->TextWriter
--->BufferedWriter
這樣就會發現裝飾設計模式,優化加強功能的部分。比繼承要靈活不少。
能夠在讀一行的基礎上添加一個行號。
class MyLineNumberReader extends MyBufferedReader {
private int number;
MyLineNumberReader(Reader r) {
super(r);
}
public String myReadLine(){
number++;
return super.myReadLine();
}
public void setNumber(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
}