黑馬程序員_day23_流的操作

----------- android培訓java培訓、java學習型技術博客、期待與您交流! ------------

一、裝飾設計模式

裝飾設計模式。

解決的問題:給已有的對象提供增強額外的功能。還不用對原有對象進行修改。 

比繼承更爲靈活。

 Writer

|--TextWriter

|--MediaWriter

現有一個體系用於各種數據的寫入。

但是,發現寫入效率有點低。想要對其進行效率的提高。

可以使用緩衝技術來完成的。

已有對象中的寫入方法,不夠高效,可以通過派生子類的形式對其進行復寫,定義高效的寫入動作。

 Writer

|--TextWriter

|--BufferTextWriter

  |--MediaWriter

|--BufferMediaWriter

|--DataWriter

|--BufferDataWriter

通過繼承的方式提高了效率。

但是對於擴展性是一個問題。而且所需的功能越多,子類就越多。

如何解決這個問題呢?優化!

既然都需要緩衝,對數據寫入效率進行提高 。

可以轉變一下思想,這樣來做,將緩衝技術單獨進行封裝。

哪個對象需要緩衝,就把哪個對象傳遞給緩衝對象即可。 

 class Buffer{

Buffer(TextWriter w){

}

Buffer(MediaWriter w){

}

}

 體系就變成了這樣:

 Writer

|--TextWriter

  |--MediaWriter

  |--BufferWriter

BufferWriter的出現,增強了Writer體系中的功能。

這種設計方式比原理更爲靈活,避免了繼承的臃腫。

將這樣解決方式就定義了一個名稱方便於後人使用:裝飾設計模式。

記住:裝飾類和被裝飾類都所屬於同一個體系。 

 二、行號裝飾類

public static void main(String[] args) throws IOException {

FileReader fr = new FileReader("tempfile\\demo.java");

LineNumberReader lnr = new LineNumberReader(fr);

String line = null;

lnr.setLineNumber(100);

while((line=lnr.readLine())!=null){

System.out.println(lnr.getLineNumber()+":"+line);

}

lnr.close();

}

三、字符流:

FileReader

FileWriter

BufferedReader

BuffereWriter

字節流。

InputStream  OutputStream

FileInputStream FileOutputStream

BufferedInputStream BufferedOutputStream

轉換流:

字節流--->字符流的橋樑。InputStreamReader 

字符流--->字節流的橋樑。OutputStreamWriter

public static void main(String[] args) throws IOException {

需求:將一個字符串寫入一個文件中。使用FileOutputStream來演示。

FileOutputStream fos = new FileOutputStream("tempfile\\fos.txt");

fos.write("abcdef".getBytes());//字節流的直接操作文件寫入時,直接將數據寫入到目的地。

爲啥FileWriter就需要刷呢?

那是因爲FileWriter底層使用了字節流在操作字符數據時,會先將這些數據進行臨時存儲,並查指定的編碼表。按照指定的編碼表中的內容寫入到目的地。

"你好"FileWriter ---> 編碼表 GBK--->數字字節--->目的地。

而字節流處理的數據不一定都是文字數據,所以是不需要指定查表的。 

直接在操作文件數據時,就將具體的字節數據寫入到目的地。

fos.flush();使用的是父類OutputStreamflush。該方法什麼都沒有做,只有OutputStram某一些子類定義了該方法的具體內容。 

fos.close();//必須有,因爲要關閉資源。

}

需求:讀取一個文件。用字節流。

int ch = fis.read();

System.out.println("ch="+ch);

//一次讀一個,打一個。

int ch = 0;

while((ch=fis.read())!=-1){

System.out.println((char)ch);

}

//讀取並存儲到數組,將數組打印。以該種方式。

byte[] buf = new byte[1024];

int len = 0;

while((len=fis.read(buf))!=-1){

System.out.println(new String(buf,0,len));

}

//直接創建一個剛剛好的大小的數組緩衝區。

byte[] buf = new byte[fis.available()];//如果文件過大,內存溢出,bang 一聲!慎用!//

fis.read(buf);//將數據存儲到剛剛好的數組中。

System.out.println(new String(buf));

fis.read();

System.out.println(fis.available());//獲取流關聯的文件的字節數。

fis.close();

四、複製mp3

1自定義數組緩衝區的方式。 

public static void copy_1() throws IOException {

//1,讀取流對象,和mp3關聯。

FileInputStream fis = new FileInputStream("C:\\0.mp3");

//2,寫入流對象,明確存儲mp3數據的目的。

FileOutputStream fos = new FileOutputStream("c:\\1.mp3");

//3,定義一個字節緩衝區。

byte[] buf = new byte[1024*8];

int len = 0;

while((len=fis.read(buf))!=-1){

fos.write(buf,0,len);

}

fos.close();

fis.close();

}

2不建議。使用剛剛好的緩衝區。因爲文件過大會溢出。

public static void copy_3() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\3.mp3");

byte[] buf = new byte[fis.available()];

fis.read(buf);

fos.write(buf);

fos.close();

fis.close();

}

3使用字節流已有的緩衝區。 

public static void copy_2() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\2.mp3");

BufferedInputStream bufis = new BufferedInputStream(fis);

BufferedOutputStream bufos = new BufferedOutputStream(fos);

int by = 0;

while((by=bufis.read())!=-1){

bufos.write(by);

}

bufos.close();

bufis.close();

}

4讀一個 寫一個

public static void copy_4() throws IOException {

FileInputStream fis = new FileInputStream("C:\\0.mp3");

FileOutputStream fos = new FileOutputStream("c:\\4.mp3");

int by = 0;

while((by=fis.read())!=-1){

fos.write(by);

}

fos.close();

fis.close();

五、鍵盤錄入

讀取鍵盤錄入。 

public static void readKey() throws IOException{

//獲取到讀取鍵盤錄入的流對象。類型是InputStream

InputStream in = System.in;

//用流讀取數據。如果沒有數據錄入,那麼控制檯會一致等待輸入。read方法就是一個阻塞式的方式。 

int ch = in.read();

System.out.println("ch="+ch);

int ch1 = in.read();

System.out.println("ch1="+ch1);

int ch2 = in.read();

System.out.println("ch2="+ch2);

in.close();//不需要關閉。 

//注意:系統中獲取的流對象都是唯一的,如果將其關閉,就不能在使用了。

//想要在使用只有重新再次運行這個程序纔可以。 

//所以一般情況下,從System獲取到的流對象,一般不需要關閉。隨着程序的停止而結束。 

// InputStream in2 = System.in;這裏會出錯 。

// int ch4 = in2.read();

// System.out.println("ch4="+ch4);

六、鍵盤錄入練習

 需求:讀取鍵盤錄入的數據,將這些數據轉成大寫打印在屏幕上,

如果錄入的是 over, 程序結束。 

 思路:

1,通過鍵盤錄入讀取字節數據。

2,將這些讀到的字節數據進行存儲以變成字符串。

3,對這個字符串進行判斷。如果不是over就將其轉成大寫打印。如果是over就結束。 

public static void readKey2() throws IOException {

//1,獲取鍵盤錄入流對象。 

InputStream in = System.in;

//2,定義一個容器用於存儲讀取到的字節。

StringBuilder sb = new StringBuilder();

//3,循環讀取鍵盤。

int ch = 0;

while((ch=in.read())!=-1){

//需要對讀取到的字節進行判斷。

//如果是/r 或者 /n,不存儲,並視爲一次錄入內容結束符。對之前的錄入數據進行判斷。

if(ch=='\r')

continue;

if(ch=='\n'){

String s = sb.toString();

if("over".equals(s)){//記住:如果要使用鍵盤錄入,一定要自定義結束標記。

break;

}

else{

System.out.println(s.toUpperCase());

//清空緩衝區。 

sb.delete(0, sb.length());

}

}

else

sb.append((char)ch);

}

}

七、轉換流 

既然鍵盤錄入轉成大寫輸出,並判斷over結束的程序中

使用了到對字節數據的存儲,並對回車符進行判斷。

 發現這個功能和readLine方法一致。

因爲readLine是字符流BufferedReader對象中過的方法。

而鍵盤錄入是字節流。

能不能將這個字節讀取流轉成字符流呢?因爲BufferedReader只能對字符流進行裝飾 。

這就用到了轉換流

轉換流:

字節流--->字符流的橋樑。InputStreamReader 

字符流--->字節流的橋樑。OutputStreamWriter

從鍵盤讀取數據,轉成大寫,顯示在屏幕上。 

獲取鍵盤錄入,數據源。

InputStream in = System.in;

爲了處理文字數據方便。將字節數據轉成字符數據.這個功能在轉換流中。InputStreamReader

InputStreamReader isr = new InputStreamReader(in);

//爲了提高了讀取的效率。使用緩衝區。 

BufferedReader bufr = new BufferedReader(isr);

//打印到顯示器上。目的。

OutputStream out = System.out;

//因爲要打印到顯示器上的數據都是文字數據。所以必須將這些文字數據轉成字節數據。

//具備這個功能的對象是OutputStreamWriter.

OutputStreamWriter osw = new OutputStreamWriter(out);

//爲了提高寫入的效率。

BufferedWriter bufw = new BufferedWriter(osw);

//頻繁的讀寫操作。 

String line = null;

while((line=bufr.readLine())!=null){

if("over".equals(line))

break;

bufw.write(line.toUpperCase());

bufw.newLine();//newLine()需要有BufferedWriter對象

bufw.flush();

}

//因爲是從System獲取的流可以不關閉,隨着系統的結束而結束。

bufw.close();

bufr.close();

}

八、流的操作規律:

規律就是四個明確?

1,明確源和目的。

源:InputStream   Reader 一定是被讀取的。

目的:OutputStream  Writer 一定是被寫入的。 

2,處理的數據是否是純文本的數據?

是:使用字符流。Reader Writer

否:使用字節流。 InputStream OutputStream

如果是源並且是純文本,Reader

如果是目的並且是純文本,Writer

到這裏,兩個明確確定完,就可以確定出要使用哪個體系。

接下來,就應該明確具體這個體系要使用哪個具體的對象。

3,明確數據所在的設備:

源設備:

鍵盤(System.in)

硬盤(FileXXX)

內存(數組)

網絡(Socket)

目的設備:

顯示器(控制檯System.out)

硬盤(FileXXX)

內存(數組)

網絡(Socket)

具體使用哪個對象就可以明確了。

4,明確是否需要額外功能?

1,是否需要高效?緩衝區Buffered

2,是否需要轉換?轉換流

後面會學到更多。

九、需求練習

需求1:複製一個文本文件。

直接明確具體對象並創建。

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("b.txt");

然後是頻繁的讀寫操作。

需要額外功能嗎?

需要,高效。 使用緩衝區。

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));

需求3:讀取鍵盤錄入,存儲到一個文件中。

明確是否是純文本?一般鍵盤錄入的都是文字,所以是純文本的。 

InputStream in = System.in;

FileWriter fw = new FileWriter("a.txt");

需要將鍵盤錄入的字節轉成字符。

使用轉換流。而且是 將字節-->字符的轉換流對象。InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);

FileWriter fw = new FileWriter("a.txt");

需要,高效。

BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bufw = new BufferedWriter(new FileWriter("a.txt"));

需求4:讀取一個文本文件,顯示到顯示器上。

FileReader fr = new FileReader("a.txt");

OutputStream out = System.out;

需要將已有的字符數據轉成字節。字符-->字節的橋樑 OutputStreamWriter

FileReader fr = new FileReader("a.txt");

OutputStreamWriter osw = new OutputStreamWriter(System.out);

需要高效。

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWrier(System.out));

需求5:讀取一個文本文件,將文件中文本按照指定的編碼表UTF-8寫入到另一個文件中。

FileReader fr = new FileReader("a.txt");

FileWriter fw = new FileWriter("b.txt");

這樣做不行,滿足不了需求,爲什麼呢?

因爲這個兩個對象在操作文本數據,都是用了默認的編碼表。在我的本機中默認碼錶是GBK.而需求中希望寫入到文件的數據是按照utf-8的碼錶。其實這兩個對象就是字節流+默認編碼表。 

源對象不變。

FileReader fr = new FileReader("a.txt");

需要目的爲指定編碼表。

這時就要用到轉換流。因爲轉換流中可以指定具體的編碼表。 需要往裏傳遞一個字節流,而且要操作文件,FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8");

需要高效

BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));

BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8"));

----------- android培訓java培訓、java學習型技術博客、期待與您交流! ------------


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章