---------- android培訓、java培訓、期待與您交流! ----------
一、IO概述
1、IO:是Input、Output的縮寫。
2、特點:
(1)用于處理設備間的數據傳輸。
(2)Java對數據的處理是通過“流”完成的。
(3)Java用于操作流的對象都在IO包中。
(4)流按操作分為兩種:字節流和字符流。
(5)流按流向分為:輸入流和輸出流(輸入輸出是相對于“內存”而言的)。
3、IO流常用基類
(1)字節流abstract基類:InputStream、OutputStream;
(2)字符流抽象基類:Reader、Writer;
二、字符流(Reader、Writer)
(一)概述
字符流只用于處理文字數據,是字節流讀取文字字節數據后,不直接操作而是先查指定的編碼表,獲取對應的文字。簡單說:字符流 = 字節流+編碼表
(二)寫入字符流(Writer)
1、“寫入字符流”操作步驟
(1)創建時,要明確文件存儲路徑。如果文件不存在,則自動創建文件。如果文件存在,則會覆蓋原文件。代碼示例:
FileWtriter fw = new FileWriter("d://d.txt");
(2)調用Writer對象中的write(String s)方法,將數據寫入到“臨時存儲緩沖區”中。代碼示例:
fw.write("abcde");
(3)調用flush()方法,刷新該流的緩沖,將數據刷新到目的地中。代碼示例:
fw.flush(); //可以用多次
(4)調用close()方法,關閉流資源。代碼示例:
fw.close();//但是關閉前會刷新一次內部的緩沖數據,并將數據刷新到目的地中,只能用一次。
注意:close()和flush()區別:flush()刷新后,流可以繼續使用;而close()刷新后,將會關閉流,不可再寫入字符流。
2、FileWriter細節
(1)換行
Windows系統中的換行是/r/n,而linux系統中的換行是/n。為了能夠適應不同的操作系統,java可以獲取系統換行。格式如下
System.getPRoperty(“line.sepatator”);
(2)續寫
如果再FileWriter的構造函數中加入true,可以實現對文件實行續寫。格式如下:
FileWtriter fw = new FileWriter("d://d.txt" , true);
(3)IO異常處理
將FileWriter對象(FileWriter fw = null)聲明在try{}catch(){}外面。
在finally中,關閉流對象,判斷fw是否為空,不為空時,才可以用try{}catch(){}來處理fw.close()。否則,會出現java.lang.NullPointerException。
3、FileWriter總結
(1)其實java自身不能寫入數據,而是調用系統內部方式完成數據的書寫,使用系統資源后,一定要關閉資源。
(2)文件的數據的續寫是通過構造函數 FileWriter(Strings,boolean append),在創建對象時,傳遞一個true參數,代表不覆蓋已有的文件。并在已有文件的末尾處進行數據續寫。(windows系統中的文件內換行用/r/n兩個轉義字符表示,在linux系統中只用/n表示換行)
(3)由于在創建對象時,需要指定創建文件位置,如果指定的位置不存在,就會發生IOException異常,所以在整個步驟中,需要對IO異常進行try處理。
(三)讀取字符流(Reader)
1、“讀取字符流”操作步驟
(1)創建一個文件讀取流對象,和指定名稱的文件相關聯。要保證該文件已經存在,若不存在,將會發生異常FileNotFoundException。代碼示例:
FileReader fr = new FileReader(“d://demo.txt”);
(2)調用讀取流對象的read()方法。read()有兩種讀取方式:一種是讀取單個字符。另一種是通過字符數組進行讀取。兩種讀取方式的代碼示例:
① 讀取單個字符方式:int ch = fr.read();
② 讀取字符數組方式:
1 char[] buf = new char[1024];2 Int len = 0;3 While(( len = fr.read(buf))!=-1){4     System.out.print( new String(buf , 0 , len));5 }(3)讀取后調用close()方法,關閉流資源。代碼示例:
fr.close();
2、FileReader總結
(1)定義文件路徑時,可以用“/”或者“//”。
(2)在創建一個文件時,如果目錄下有同名文件將被覆蓋。
(3)在讀取文件時,必須保證該文件已存在,否則出異常。
(四)字符流練習:
/*
需求:將c盤一個文本文件復制到d盤。
思路:1、需要讀取源;2、將讀到的源寫入到目的地;
步驟:
1、讀一個文件,是字符讀取流和文件關聯;
2、創建一個目的文件,用于存儲讀到的數據;
3、頻繁的讀寫;
4、關閉流資源;
*/
 1 import java.io.*; 2 class ReaderWriterTest { 3     public static void main(String[] args) { 4         // 調用復制方法 5         // copy_1(); 6         copy_2(); 7     } 8     // 用第一種讀取方式進行復制 9     public static void copy_1() {10         FileWriter fw = null;11         FileReader fr = null;12         try {13             // 關聯讀取和寫入的文件14             fw = new FileWriter("D://HelloWorld.java");15             fr = new FileReader("C://HelloWorld.java");16             for (int ch = 0; (ch = fr.read()) != -1;) {17                 fw.write(ch);// 一個字符一個字符寫入18             }19         } catch (IOException e) {20             throw new RuntimeException("讀寫失敗");21         } finally {22             if (fr != null)23                 try {24                     fr.close();// 對讀取流和寫入流分別關閉25                 } catch (IOException e) {26                 }27             if (fw != null)28                 try {29                     fw.close();30                 } catch (IOException e) {31                 }32         }33     }34     // 第二種讀取方式進行復制35     public static void copy_2() {36         FileWriter fw = null;37         FileReader fr = null;38         try {39             // 關聯讀取和寫入的文件40             fw = new FileWriter("D://HelloWorld.java");41             fr = new FileReader("C://HelloWorld.java");42             char[] arr = new char[1024];43             for (int len = 0; (len = fr.read(arr)) != -1;) {44                 fw.write(arr, 0, len);// 利用數組一次存入數組中的字符45             }46         } catch (IOException e) {47             throw new RuntimeException("讀寫失敗");48         } finally {49             try {50                 if (fr != null)51                     fr.close();52             } catch (IOException e) {53             } finally {54                 if (fw != null)55                     try {56                         fw.close();57                     } catch (IOException e) {58                     }59             }60         }61     }62 }三、字符流緩沖區
(一)概述
1、字符流緩沖區的作用:提高了對數據的讀寫效率。
2、對應的類:BufferedWriter以及BufferedReader,要結合流,才可以使用。
(二)BufferedWriter
1、操作步驟
(1)創建一個字符寫入流對象,代碼示例:
FileWriter fw = new FileWriter("demo.txt");
(2)為了提高字符寫入流效率,加入緩沖技術,將需要被提高效率的流對象作為參數傳遞給緩沖區的構造函數,代碼示例:
BufferedWriter bufw = new BufferedWriter(fw);
(3)調用write方法寫入數據到指定文件,代碼示例:
bufw.write ("abcde");
(4)刷新緩沖區,代碼示例:
bufw.flush();
(5)關閉流資源,,代碼示例:
bufw.close();
2、小細節:BufferedWriter提供了跨平臺的換行符newLine()方法,格式:bufw.newLine();
(三)BufferedReader
1、作用
從字符輸入流中讀取文本,緩沖各個字符,從而實現字符、數組和行的高效讀取。
2、特點
BufferedReader提供了一次讀一行的方法readLine(),方便于文本數據的獲取,當返回null時表示讀到文件末尾。readLine方法返回的時候,只返回回車符之前的數據內容。并不返回回車符。
3、readLine()原理
使用了讀取緩沖區的read()方法,將讀取到的字符進行緩沖并判斷換行標記,將標記前的緩存數據變成字符串返回。
4、BufferedReader操作步驟
(1)創建一個讀取流對象和文件相關聯,
FileReader fr = new FileReader("demo.txt");
(2)為了提高效率、加入緩沖技術、將字符讀取流對象作為參數傳遞給緩沖區對象的構造函數。
BufferedReader bufr = new BufferedReader(fr);
(3)調用該readLine()方法一行一行讀取,如果到達文件末尾,則返回null
String str = bufr.readLine();
(4)關閉流資源
bufr.close();
(四)練習
/* 需求:使用緩沖技術copy一個文本文件 */
import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class CopyTextByBufTest {    public static void main(String[] args) throws IOException {        FileReader fr = new FileReader("buf.txt");        BufferedReader bufr = new BufferedReader(fr);        FileWriter fw = new FileWriter("buf_copy.txt");        BufferedWriter bufw = new BufferedWriter(fw);        String line = null;        while((line=bufr.readLine())!=null){            bufw.write(line);            bufw.newLine();            bufw.flush();        }//單個字符讀取方式        //int ch = 0;        //while((ch=bufr.read())!=-1){        //    bufw.write(ch);        //}        bufw.close();        bufr.close();    }}(五)自定義緩沖區
 1 /*需求:模擬BufferedReader,自定義一個MyBufferedReader緩沖區 */ 2 import java.io.*; 3 //自定義緩沖類   4 class MyBufferedReader extends Reader { 5     private Reader r;// 定義接收的流對象 6     MyBufferedReader(Reader r) { 7         this.r = r; 8     } 9     // 自定義整行讀取10     public String myReadLine() throws IOException {11         // 創建一個容器,用來存儲一行的字符12         StringBuilder sb = new StringBuilder();13         // 一個字符一個字符讀取14         for (int ch = 0; (ch = r.read()) != -1;) {15             if (ch == '/r')// 如果遇到換行符,則繼續16                 continue;17             if (ch == '/n')// 如果遇到回車符,表示該行讀取完畢18                 return sb.toString();19             else20                 sb.append((char) ch);// 將該行的字符添加到容器21         }22         if (sb.length() != 0)// 如果讀取結束,容器中還有字符,則返回元素23             return sb.toString();24         return null;25     }26     // 復寫父類中的抽象方法27     public int read(char[] cbuf, int off, int len) throws IOException {28         return r.read(cbuf, off, len);29     }30     // 復寫父類的close方法31     public void close() throws IOException {32         r.close();33     }34 }35 36 // 測試MyBufferedReader37 class MyBufferedReaderDemo {38     public static void main(String[] args) {39         MyBufferedReader mbr = null;40         try {41             mbr = new MyBufferedReader(new FileReader("d://HelloWorld.java"));42             for (String line = null; (line = mbr.myReadLine()) != null;) {43                 System.out.println(line);// 顯示效果44             }45         } catch (IOException e) {46             throw new RuntimeException("讀取數據失敗");47         } finally {48             try {49                 if (mbr != null)50                     mbr.close();51             } catch (IOException e) {52                 throw new RuntimeException("讀取流關閉失敗");53             }54         }55     }56 }(六)LineNumberReader類
在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設置行號:
setLineNumber();//設置初始行號
getLineNumber();//獲取行號
(七)裝飾設計模式
1、對一組對象的功能進行增強時,就可以使用裝飾模式來解決問題。
2、特點:裝飾類通常都會通過構造方法接收被裝飾的對象,基于被裝飾的對象的功能,提供更強的功能。
3、“裝飾和繼承”的異同?
(1)相同點:進行功能的擴展和增強,
(2)區別:裝飾模式比繼承要靈活、避免了繼承體系的臃腫,降低了類與類之間的繼承關系。裝飾類和被裝飾的類通常都是屬于一個體系,有同一個接口或父類。
注:在定義類的時候,不要以繼承為主;可通過裝飾設計模式進行增強類功能。靈活性較強,當裝飾類中的功能不適合,可再使用被裝飾類的功能。
四、字節流(FileInputStream、FileOutputStream)
(一)概述
1、字節流和字符流的基本操作是相同的,它不僅可以操作文本數據,還可以操作其他媒體類文件。
2、由于硬盤上的數據都是以“字節”存儲的,所以字節流對象可直接將數據寫入到文件中,而可以不用再進行刷流動作。
3、讀寫字節流:
(1)InputStream:輸入流(讀)
(2)OutputStrea:輸出流(寫)
4、InputStream特有方法:
int available();//返回文件中的字節個數
注:可以利用此方法來指定讀取方式中傳入數組的長度,從而省去循環判斷。但是如果文件較大,而虛擬機啟動分配的默認內存一般為64M。當文件過大時,此數組長度所占內存空間就會溢出。所以,此方法慎用,當文件不大時,可以使用。
(二)FileInputStream、FileOutputStream
1、FileInputStream:InputStream常用子類之一,從文件系統中的某個文件中獲得輸入字節。
2、FileOutputStream:OutputStream常用子類之一,用于寫入諸如圖像數據之類的原始字節的流。
3、練習:復制圖片
 1 import java.io.*; 2 class CopyPic { 3     public static void main(String[] args) { 4         // 常用方法復制 5         byteArrayCopy(); 6  7         // 利用輸入流的available方法進行復制 8         // 利用available方法對復制文件大小有限制,慎用 9         availableCopy();10     }11     // 使用available方法進行復制12     public static void availableCopy() {13         FileInputStream fis = null;14         FileOutputStream fos = null;15         try {16             // 關聯要復制的文件17             fis = new FileInputStream("C://1.jpg");18             // 指定復制的路徑19             fos = new FileOutputStream("C://copy_1.jpg");20             // 利用available方法指定數組長度21             byte[] buf = new byte[fis.available()];22             fis.read(buf);// 復制關聯文件數據23             fos.write(buf);// 粘貼到指定路徑24         } catch (IOException e) {25             throw new RuntimeException("圖片復制失敗");26         } finally {27             try {28                 if (fis != null)29                     fis.close();// 關閉輸入字節流30             } catch (IOException e) {31                 throw new RuntimeException("讀取字節流關閉失敗");32             }33             try {34                 if (fos != null)35                     fos.close();// 關閉輸出字節流36             } catch (IOException e) {37                 throw new RuntimeException("寫入字節流關閉失敗");38             }39         }40     }41     // 使用讀數組方式進行復制42     public static void byteArrayCopy() {43         FileInputStream fis = null;44         FileOutputStream fos = null;45         try {46             // 關聯要復制的文件47             fis = new FileInputStream("C://2.jpg");48             // 指定復制的路徑49             fos = new FileOutputStream("C://copy_2.jpg");50             // 利用數組的讀取方式51             byte[] buf = new byte[1024];52             int len = 0;53             while ((len = fis.read(buf)) != -1){54                 fos.write(buf, 0, len);// 粘貼到指定路徑55             }56         } catch (IOException e) {57             throw new RuntimeException("圖片復制失敗");58         } finally {59             try {60                 if (fis != null)61                     fis.close();// 關閉輸入字節流62             } catch (IOException e) {63                 throw new RuntimeException("讀取字節流關閉失敗");64             }65             try {66                 if (fos != null)67                     fos.close();// 關閉輸出字節流68             } catch (IOException e) {69                 throw new RuntimeException("寫入字節流關閉失敗");70             }71         }72     }73 }五、字節流緩沖區(BufferedInputStream、BufferedOutputStream)
1、作用:為了提高字節流的讀寫效率。
2、練習:分別用一般方式和字節緩沖區方式實現mp3文件的復制
 1 import java.io.BufferedInputStream; 2 import java.io.BufferedOutputStream; 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 public class CopyMp3Test { 7     public static void main(String[] args) throws IOException { 8         //普通方式復制mp3方法 9         OrdinayMethod();10         11         //字節緩沖方式復制mp3方法12         BufferedCopyMethod();13     }14     //字節緩沖方式復制功能定義15     public static void BufferedCopyMethod() throws IOException {16         FileInputStream fis = new FileInputStream("c://0.mp3");17         BufferedInputStream bufis = new BufferedInputStream(fis);18 19         FileOutputStream fos = new FileOutputStream("c://2.mp3");20         BufferedOutputStream bufos = new BufferedOutputStream(fos);21 22         int ch = 0;23         while ((ch = bufis.read()) != -1) {24             bufos.write(ch);25         }26 27         bufos.close();28         bufis.close();29     }30     ////普通方式復制功能定義31     public static void OrdinayMethod() throws IOException {32         FileInputStream fis = new FileInputStream("c://0.mp3");33         FileOutputStream fos = new FileOutputStream("c://1.mp3");34 35         byte[] buf = new byte[1024];36         int len = 0;37         while ((len = fis.read(buf)) != -1) {38             fos.write(buf, 0, len);39         }40 41         fos.close();42         fis.close();43     }44 }六、流操作(鍵盤輸入流、轉換流)
(一)標準輸入輸出流
1、System.in:是“標準”輸入流,其類型是static InputStream類型,通常對應于鍵盤輸入或者由主機環境或用戶指定的另一個輸入源。。
2、System.out:是“標準”輸出流,其類型是PrintStrea,此流對應于顯示器輸出或者由主機環境或用戶指定的另一個輸出目標。
(二)讀取鍵盤錄入
InputStream in = System.in.
int ch = in.read(); //此句代碼是阻塞式方法
in.close(); //鍵盤輸入只有一個,一關閉就不可以再輸入,通常不建議關。
(三)整行錄入
當使用輸入流進行鍵盤錄入時,只能一個字節一個字節進行錄入。為了提高效率,可以自定義一個數組將一行字節進行存儲。當一行錄入完畢,再將一行數據進行顯示。這種正行錄入的方式,和字符流讀一行數據的原理是一樣的。也就是readLine方法。
那么能不能直接使用readLine方法來完成鍵盤錄入的一行數據的讀取呢?readLine方法是字符流BufferedReader類中方法。而鍵盤錄入的read方法是字節流InputStream的方法。
那么能不能將字節流轉成字符流再使用字符流緩沖區的readLine方法呢?這就需要用到轉換流。
(四)轉換流(InputStreamReader、OutputStreamWriter)
1、轉換流:字符流與字節流之間的橋梁,方便了字符流與字節流之間的轉換操作。
2、InputStreamReader:將字節流通向字符流的橋梁:
(1)定義鍵盤錄入
InputStream in = System.in;
(2)定義轉換流:字節流——>字符流
InputStreamReader isr = new InputStreamReader(in);
(3)定義字符流緩沖區,使用BufferedReader
BufferedReader br = new BufferedReader(isr);
3、OutputStreamWriter:字符流通向字節流的橋梁
字符通向字節:錄入的是字符,存到硬盤上的是字節,操作與InputStreamReader轉換流類似。
4、總結:
(1)謹記:鍵盤錄入寫法:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
(2)謹記:控制臺輸出寫法
BufferedWriter bufw = new BufferedRWriter(new OutputStreamWriter(System.out));
注:System.in可以替換為new FileInputStream(“file”)。System.out可以替換為new FileOutputStream(“file”)。
5、什么時候使用轉換流呢?
(1)源或者目的對應的設備是“字節流”,但是操作的確實“文本數據”,可以使用轉換流作為橋梁。
(2)一旦操作文本涉及到具體的指定編碼表時,必須使用轉換流。
6、轉換流應用代碼示例:
 1 /* 2 需求:將鍵盤錄入的數據,顯示在控制臺,當輸入over時,表示結束。 3 源:鍵盤錄入。 4 目的:控制臺。 5 */ 6 import java.io.*;  7 class TransStreamDemo{ 8     public static void main(String[] args)throws IOException{ 9         10         //鍵盤錄入裝飾寫法11         BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));12   13         //控制臺輸出裝飾寫法14         BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));15   16         String line = null;17         while(( line = bufr.readLine())! = null){18             if("over".equals(s))19                 break;20             bufw.write(s.toUpperCase());//寫入數據21             bufw.newLine();//換行22             bufw.flush();//刷新 23         }24         bufw.close();//關閉流資源25         bufr.close();26     }27 }(五)流操作的基本規律
1、要知道開發時用那些對象,只要通過四個明確即可:
(1)明確源和目的
---源:InputStream、Reader
---目的:OutputStream、Writer
(2)明確詩句是否是文本數據
---源:是純文本:Reader
否:InputStream
---目的:是純文本:Writer
否:OutputStream
* 到此,可以明確具體要用到哪個體系。
(3)明確具體的設備
---源設備:硬盤:File
鍵盤:System.in
內存:數組
網絡:Socket流
---目的設備:硬盤:File
鍵盤:System.in
內存:數組
網絡:Socket流
(4)是否需要其他額外功能
* 是否要高效(緩沖區):是添加前綴Buffered
* 是否轉換流:用InputStreamReader / OutputStreamWriter
2、基本規律應用練習
需求1:復制一個文本文件。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是純文本?
是!
源:Reader
目的:Writer
3、明確具體設備。
源:硬盤:File
目的:硬盤:File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
4、需要額外功能嗎?
需要,需要高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
================================================
需求2:讀取鍵盤錄入信息,并寫入到一個文件中。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是純文本呢?
是,
源:Reader
目的:Writer
3、明確設備
源:
鍵盤。System.in
目的:硬盤。File
InputStream in = System.in;
FileWriter fw = new FileWriter("b.txt");
這樣做可以完成,但是麻煩。將讀取的字節數據轉成字符串。再由字符流操作。
4、需要額外功能嗎?
需要。轉換。將字節流轉成字符流。因為名確的源是Reader,這樣操作文本數據做便捷。
所以要將已有的字節流轉成字符流。使用字節-->字符 。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("b.txt");
還需要功能嗎?
需要:想高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
===================================================
需求3:將一個文本文件數據顯示在控制臺上。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是純文本呢?
是,
源:Reader
目的:Writer
3、明確具體設備
源:硬盤:File
目的:控制臺:System.out
FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;//PrintStream
4、需要額外功能嗎?
需要,轉換。
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 OutputStreamWriter(System.out));
================================================================
需求4:讀取鍵盤錄入數據,顯示在控制臺上。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、是否是純文本呢?
是,
源:Reader
目的:Writer
3、明確設備。
源:
鍵盤:System.in
目的:控制臺:System.out
InputStream in = System.in;
OutputStream out = System.out;
4、明確額外功能?
需要轉換,因為都是字節流,但是操作的卻是文本數據。
所以使用字符流操作起來更為便捷。
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
為了將其高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
============================================================
5、將一個中文字符串數據按照指定的編碼表寫入到一個文本文件中.
1、目的。OutputStream,Writer
2、是純文本,Writer。
3、設備:硬盤File
FileWriter fw = new FileWriter("a.txt");
fw.write("你好");
注意:既然需求中已經明確了指定編碼表的動作。那就不可以使用FileWriter,因為FileWriter內部是使用默認的本地碼表。只能使用其父類OutputStreamWriter。OutputStreamWriter接收一個字節輸出流對象,既然是操作文件,那么該對象應該是FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
4、需要高效嗎?
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
---------- android培訓、java培訓、期待與您交流! ----------
新聞熱點
疑難解答