java基礎(四):談談java中的IO流

1.字節流

1.1.字節輸出流output

1.1.1.數據寫入文件中

  經過api查找output。找到不少,其中java.io.OutputStream,OutputStream: 輸出字節流的超類。html

  基本特色:java

  一、操做的數據都是字節。編程

  二、定義了輸出字節流的基本共性功能。api

  三、輸出流中定義都是寫write方法。操做字節數組write(byte[]),操做單個字節write(byte)。數組

  子類有規律:全部的子類名稱後綴是父類名,前綴名是這個流對象功能bash

  想要操做文件: FileOutputStreamapp

public class FileOutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //需求:將數據寫入到文件中。
        //建立存儲數據的文件。
        File file = new File("c:\\file.txt");
        //建立一個用於操做文件的字節輸出流對象。一建立就必須明確數據存儲目的地。
        //輸出流目的是文件,會自動建立。若是文件存在,則覆蓋。
        FileOutputStream fos = new FileOutputStream(file);
        //調用父類中的write方法。
        byte[] data = "abcde".getBytes();
        fos.write(data);
        //關閉流資源。
        fos.close();
    }
}
複製代碼

1.1.2.給文件中續寫和換行

  咱們知道直接new FileOutputStream(file)這樣建立對象,會覆蓋原有的文件,那麼咱們想在原有的文件中續寫內容怎麼辦呢?繼續查閱FileOutputStream的API。發如今FileOutputStream的構造函數中,能夠接受一個boolean類型的值,若是值true,就會在文件末位繼續添加ide

public class FileOutputStreamDemo2 {
    public static void main(String[] args) throws Exception {
        File file = new File("c:\\file.txt");
        FileOutputStream fos = new FileOutputStream(file, true);
        String str = "\r\n"+"itcast";
        fos.write(str.getBytes());
        fos.close();
    }
}
複製代碼

1.1.3.IO異常的處理

  咱們在開發中應該如何處理這些異常呢?函數

public class FileOutputStreamDemo3 {
    public static void main(String[] args) {

        File file = new File("c:\\file.txt");
        //定義FileOutputStream的引用
        FileOutputStream fos = null;
        try {
            //建立FileOutputStream對象
            fos = new FileOutputStream(file);
            //寫出數據
            fos.write("abcde".getBytes());

        } catch (IOException e) {
            System.out.println(e.toString() + "----");
        } finally {
            //必定要判斷fos是否爲null,只有不爲null時,才能夠關閉資源
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    throw new RuntimeException("");
                }
            }
        }
    }
}
複製代碼

1.2.字節輸入流Input

1.2.1.讀取數據read方法

  經過api查找input。java.io.InputStream。InputStream:字節輸入流的超類。學習

  常見功能:

int read():讀取一個字節並返回,沒有字節返回-1.

int read(byte[]): 讀取必定量的字節數,並存儲到字節數組中,返回讀取到的字節數。

  用於讀取文件的字節輸入流對象:FileInputStream。

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("c:\\file.txt");
        //建立一個字節輸入流對象,必須明確數據源,其實就是建立字節讀取流和數據源相關聯。
        FileInputStream fis = new FileInputStream(file);
        //讀取數據。使用 read();一次讀一個字節。
        int ch = 0;
        while((ch=fis.read())!=-1){
            System.out.println("ch="+(char)ch);
        }
        // 關閉資源。
        fis.close();
    }
}
複製代碼

1.2.2.讀取數據read(byte[])方法

  在讀取文件中的數據時,調用read方法,每次只能讀取一個,太麻煩了,因而咱們能夠定義數組做爲臨時的存儲容器,這時能夠調用重載的read方法,一次能夠讀取多個字符。

public class FileInputStreamDemo2 {
    public static void main(String[] args) throws IOException {
        /*
         * 演示第二個讀取方法, read(byte[]);
         */
        File file = new File("c:\\file.txt");
        // 建立一個字節輸入流對象,必須明確數據源,其實就是建立字節讀取流和數據源相關聯。
        FileInputStream fis = new FileInputStream(file);        
        //建立一個字節數組。
        byte[] buf = new byte[1024];//長度能夠定義成1024的整數倍。        
        int len = 0;
        while((len=fis.read(buf))!=-1){
            System.out.println(new String(buf,0,len));
        }
        fis.close();
    }
}
複製代碼

2.字符流

  通過前面的學習,咱們基本掌握的文件的讀寫操做,在操做過程當中字節流能夠操做全部數據,但是當咱們操做的文件中有中文字符,而且須要對中文字符作出處理時怎麼辦呢?

2.1.字節流讀取問題

  經過如下程序讀取帶有中文件的文件。

public class CharStreamDemo {
    public static void main(String[] args) throws IOException {
        //給文件中寫中文
        writeCNText();
        //讀取文件中的中文
        readCNText();
    }    
    //讀取中文
    public static void readCNText() throws IOException {
        FileInputStream fis = new FileInputStream("c:\\cn.txt");
        int ch = 0;
        while((ch = fis.read())!=-1){
            System.out.println(ch);
        }
    }
    //寫中文
    public static void writeCNText() throws IOException {
        FileOutputStream fos = new FileOutputStream("c:\\cn.txt");
        fos.write("a傳智播客歡迎你".getBytes());
        fos.close();
    }
}
複製代碼

  上面程序在讀取含有中文的文件時,咱們並無看到具體的中文,而是看到一些數字,這是什麼緣由呢?既然看不到中文,那麼咱們如何對其中的中文作處理呢?要解決這個問題,咱們必須研究下字符的編碼過程。

2.2.編碼表

  咱們知道計算機底層數據存儲的都是二進制數據,而咱們生活中的各類各樣的數據,如何才能和計算機中存儲的二進制數據對應起來呢?這時老美他們就把每個字符和一個整數對應起來,就造成了一張編碼表,老美他們的編碼表就是ASCII表。其中就是各類英文字符對應的編碼。

編碼表:其實就是生活中字符和計算機二進制的對應關係表。

  • ascii: 一個字節中的7位就能夠表示。對應的字節都是正數。0-xxxxxxx

  • iso8859-1:拉丁碼錶 latin,用了一個字節用的8位。1-xxxxxxx 負數。

  • GB2312:簡體中文碼錶。包含6000-7000中文和符號。用兩個字節表示。兩個字節都是開頭爲1 ,兩個字節都是負數。

  • GBK:目前最經常使用的中文碼錶,2萬的中文和符號。用兩個字節表示,其中的一部分文字,第一個字節開頭是1,第二字節開頭是0

  • GB18030:最新的中文碼錶,目前尚未正式使用。

  • unicode:國際標準碼錶:不管是什麼文字,都用兩個字節存儲。

   Java中的char類型用的就是這個碼錶。char c = 'a';佔兩個字節。

   Java中的字符串是按照系統默認碼錶來解析的。簡體中文版 字符串默認的碼錶是GBK。

  • UTF-8:基於unicode,一個字節就能夠存儲數據,不要用兩個字節存儲,並且這個碼錶更加的標準化,在每個字節頭加入了編碼信息(後期到api中查找)。

  能識別中文的碼錶:GBK、UTF-8;正由於識別中文碼錶不惟一,涉及到了編碼解碼問題。對於咱們開發而言;常見的編碼 GBK UTF-8 ISO8859-1

    文字--->(數字) :編碼。

    (數字)--->文字 : 解碼。

2.3.FileReader類介紹

  上述程序中咱們讀取擁有中文的文件時,使用的字節流在讀取,那麼咱們讀取到的都是一個一個字節。只要把這些字節去查閱對應的編碼表,就可以獲得與之對應的字符。API中是否給咱們已經提供了讀取相應字符的功能流對象呢?

  查閱FileInputStream的API,發現FileInputStream 用於讀取諸如圖像數據之類的原始字節流。要讀取字符流,請考慮使用 FileReader。若是讀取字符流,要使用FileReader,FileReader是什麼呢?

  打開FileReader的API介紹。用來讀取字符文件的便捷類。此類的構造方法假定默認字符編碼和默認字節緩衝區大小都是適當的,原來FileReader 用於讀取字符流。使用FileReader時,瞭解它的功能,看它所屬的體系頂層。

  Reader:讀取字符流的抽象超類。

    read():讀取單個字符並返回

    read(char[]):將數據讀取到數組中,並返回讀取的個數。

public class CharStreamDemo {
    public static void main(String[] args) throws IOException {
        //給文件中寫中文
        writeCNText();
        //讀取文件中的中文
        readCNText();
    }    
    //讀取中文
    public static void readCNText() throws IOException {
        FileReader fr = new FileReader("D:\\test\\cn.txt");
        int ch = 0;
        while((ch = fr.read())!=-1){
            //輸出的字符對應的編碼值
            System.out.println(ch);
            //輸出字符自己
            System.out.println((char)ch);
        }
    }
    //寫中文
    public static void writeCNText() throws IOException {
        FileOutputStream fos = new FileOutputStream("D:\\test\\cn.txt");
        fos.write("a傳智播客歡迎你".getBytes());
        fos.close();
    }
}
複製代碼

2.4.FileWriter類介紹

  既然有專門用於讀取字符的流對象,那麼確定也有寫的字符流對象,查閱API,發現有一個Writer類,Writer是寫入字符流的抽象類。其中描述了相應的寫的動做。

public class FileWriterDemo {
    public static void main(String[] args) throws IOException {
        //演示FileWriter 用於操做文件的便捷類。
        FileWriter fw = new FileWriter("d:\\text\\fw.txt");
        
        fw.write("你好謝謝再見");//這些文字都要先編碼。都寫入到了流的緩衝區中。
        
        fw.flush();
        
        fw.close();
    }
}
複製代碼

2.5.flush()和close()的區別

  flush():將流中的緩衝區緩衝的數據刷新到目的地中,刷新後,流還能夠繼續使用。

  close():關閉資源,但在關閉前會將緩衝區中的數據先刷新到目的地,不然丟失數據,而後在關閉流。流不可使用。若是寫入數據多,必定要一邊寫一邊刷新,最後一次能夠不刷新,由close完成刷新並關閉。

3.轉換流

  學習完了使用字符流對文件的簡單操做後,在學習字符流的時候,其中說若是須要指定編碼和緩衝區大小時,能夠在字節流的基礎上,構造一個InputStreamReader或者OutputStreamWriter,這又是什麼意思呢?

3.1.OutputSreamWriter類

  需求:既然識別中文的碼錶有兩個,GBK、UTF-8等,能不能將中文數據按照utf-8的方式進行文件的存儲呢?

  還能使用FileWriter嗎?不能使用了,由於FileWriter中默認的是GBK。經過FileWriter的api描述,要指定編碼表這些值,須要使用OutputStreamWriter

  OutputStreamWriter 是字符流通向字節流的橋樑:可以使用指定的 charset 將要寫入流中的字符編碼成字節。它的做用的就是,將字符串按照指定的編碼表轉成字節,在使用字節流將這些字節寫出去

public static void writeCN() throws Exception {
        //建立與文件關聯的字節輸出流對象
        FileOutputStream fos = new FileOutputStream("c:\\cn8.txt");
        //建立能夠把字符轉成字節的轉換流對象,並指定編碼
        OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
        //調用轉換流,把文字寫出去,實際上是寫到轉換流的緩衝區中
        osw.write("你好");//寫入緩衝區。
        osw.close();
    }
複製代碼

  OutputStreamWriter流對象,它到底如何把字符轉成字節輸出的呢?

  其實在OutputStreamWriter流中維護本身的緩衝區,當咱們調用OutputStreamWriter對象的write方法時,會拿着字符到指定的碼錶中進行查詢,把查到的字符編碼值轉成字節數存放到OutputStreamWriter緩衝區中。而後再調用刷新功能,或者關閉流,或者緩衝區存滿後會把緩衝區中的字節數據使用字節流寫到指定的文件中。

3.2.InputSreamReader類

  查閱InputStreamReader的API介紹,InputStreamReader 是字節流通向字符流的橋樑:它使用指定的 charset 讀取字節並將其解碼爲字符。它使用的字符集能夠由名稱指定或顯式給定,或者能夠接受平臺默認的字符集。

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        //演示字節轉字符流的轉換流
        readCN();
    }
    public static void readCN() throws IOException{
        //建立讀取文件的字節流對象
        InputStream in = new FileInputStream("c: \\cn8.txt");
        //建立轉換流對象 
        //InputStreamReader isr = new InputStreamReader(in);這樣建立對象,會用本地默認碼錶讀取,將會發生錯誤解碼的錯誤
        InputStreamReader isr = new InputStreamReader(in,"utf-8");
        //使用轉換流去讀字節流中的字節
        int ch = 0;
        while((ch = isr.read())!=-1){
            System.out.println((char)ch);
        }
        //關閉流
        isr.close();
    }
}
複製代碼

  注意:在讀取指定的編碼的文件時,必定要指定編碼格式,不然就會發生解碼錯誤,而發生亂碼現象

3.3.轉換流和子類的區別

  發現有以下繼承關係:

    OutputStreamWriter:

      FileWriter:

    InputStreamReader:

      FileReader;

  父類和子類的功能有什麼區別呢?

  OutputStreamWriter和InputStreamReader是字符和字節的橋樑:也能夠稱之爲字符轉換流。字符轉換流原理:字節流+編碼表。

  FileWriter和FileReader:做爲子類,僅做爲操做字符文件的便捷類存在。當操做的字符文件,使用的是默認編碼表時能夠不用父類,而直接用子類就完成操做了,簡化了代碼。

  InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默認字符集。

  InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。

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

  這三句代碼的功能是同樣的,其中第三句最爲便捷。

  注意:一旦要指定其餘編碼時,絕對不能用子類,必須使用字符轉換流。何時用子類呢?

  條件:

  一、操做的是文件。二、使用默認編碼。3 純文本

  總結:

  字節--->字符 : 看不懂的--->看的懂的。 須要讀。輸入流。 InputStreamReader

  字符--->字節 : 看的懂的--->看不懂的。 須要寫。輸出流。 OutputStreamWriter

4.緩衝流

  在咱們學習字節流與字符流的時候,你們都進行過讀取文件中數據的操做,讀取數據量大的文件時,讀取的速度會很慢,很影響咱們程序的效率,那麼, 我想提升速度,怎麼辦?Java中提升了一套緩衝流,它的存在,可提升IO流的讀寫速度緩衝流,根據流的分類分類字節緩衝流與字符緩衝流。

4.1.字節緩衝流

  字節緩衝流根據流的方向,共有2個

     寫入數據到流中,字節緩衝輸出流 BufferedOutputStream

    讀取流中的數據,字節緩衝輸入流 BufferedInputStream

  它們的內部都包含了一個緩衝區,經過緩衝區讀寫,就能夠提升了IO流的讀寫速度

4.1.1.字節緩衝輸出流BufferedOutputStream

  經過字節緩衝流,進行文件的讀寫操做 寫數據到文件的操做

  構造方法public BufferedOutputStream(OutputStream out)建立一個新的緩衝輸出流,以將數據寫入指定的底層輸出流。

public class BufferedOutputStreamDemo01 {
    public static void main(String[] args) throws IOException {
        
        //寫數據到文件的方法
        write();
    }

    /*
     * 寫數據到文件的方法
     * 1,建立流
     * 2,寫數據
     * 3,關閉流
     */
    private static void write() throws IOException {
        //建立基本的字節輸出流
        FileOutputStream fileOut = new FileOutputStream("abc.txt");
        //使用高效的流,把基本的流進行封裝,實現速度的提高
        BufferedOutputStream out = new BufferedOutputStream(fileOut);
        //2,寫數據
        out.write("hello".getBytes());
        //3,關閉流
        out.close();
    }
}
複製代碼

4.1.2.字節緩衝輸出流BufferedInputStream

  剛剛咱們學習了輸出流實現了向文件中寫數據的操做,那麼,如今咱們完成讀取文件中數據的操做

  構造方法

  public BufferedInputStream(InputStream in)

/*
     * 從文件中讀取數據
     * 1,建立緩衝流對象
     * 2,讀數據,打印
     * 3,關閉
     */
    private static void read() throws IOException {
        //1,建立緩衝流對象
        FileInputStream fileIn = new FileInputStream("abc.txt");
        //把基本的流包裝成高效的流
        BufferedInputStream in = new BufferedInputStream(fileIn);
        //2,讀數據
        int ch = -1;
        while ( (ch = in.read()) != -1 ) {
            //打印
            System.out.print((char)ch);
        }
        //3,關閉
        in.close();
    }
複製代碼

4.1.3.使用基本的流與高效的流完成複製文件

  咱們一直在說,高效的流速度快並高效,怎麼體現呢?須要經過一個複製文件耗時的比較過程,來體驗一下高效流帶來的快感。

/*
 * 需求:將d:\\test.avi文件進行復制
 *         採用4種方式複製
 *         方式1: 採用基本的流,一次一個字節的方式複製    共耗時 224613毫秒
 *         方式2: 採用基本的流,一個多個字節的方式賦值    共耗時     327毫秒
 *         方式3: 採用高效的流,一次一個字節的方式複製    共耗時    2047毫秒
 *         方式4: 採用高效的流,一個多個字節的方式賦值    共耗時      96毫秒
 * 
 * 數據源: d:\\test.avi
 * 目的地1: d:\\copy1.avi
 * 目的地2: d:\\copy2.avi
 * 目的地3: d:\\copy3.avi
 * 目的地4: d:\\copy4.avi
 * 
 * 實現的步驟:
 *     1,指定數據源
 *     2,指定目的地
 *     3,讀數據
 *     4,寫數據
 *     5,關閉流
 * 
 */
public class CopyAVI {
    public static void main(String[] args) throws IOException {
        //開始計時
        long start = System.currentTimeMillis();
        //方式1: 採用基本的流,一次一個字節的方式複製
        //method1("d:\\test.avi", "d:\\copy1.avi");
        //方式2: 採用基本的流,一個多個字節的方式賦值
        //method2("d:\\test.avi", "d:\\copy2.avi");
        //方式3: 採用高效的流,一次一個字節的方式複製
        //method3("d:\\test.avi", "d:\\copy3.avi");
        //方式4: 採用高效的流,一個多個字節的方式賦值
        method4("d:\\test.avi", "d:\\copy4.avi");
        
        //結束計時
        long end = System.currentTimeMillis();
        //打印耗時多少毫秒
        System.out.println("共耗時 " +(end - start)+ "毫秒");
    }
    
    //方式4: 採用高效的流,一個多個字節的方式賦值
    private static void method4(String src, String dest) throws IOException {
        //1,指定數據源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
         //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
         //3,讀數據
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len = in.read(buffer)) != -1) {
            //4,寫數據
            out.write(buffer, 0, len);
        }
         //5,關閉流
        in.close();
        out.close();
    }

    //方式3: 採用高效的流,一次一個字節的方式複製
    private static void method3(String src, String dest) throws IOException {
        //1,指定數據源
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
         //2,指定目的地
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
         //3,讀數據
        int ch = -1;
        while ((ch=in.read()) != -1) {
            //4,寫數據
            out.write(ch);    
        }        
         //5,關閉流
        in.close();
        out.close();
    }

    //方式2: 採用基本的流,一個多個字節的方式賦值
    private static void method2(String src, String dest) throws IOException {
        //1,指定數據源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,讀數據
        byte[] buffer = new byte[1024];
        int len = -1;
        while ( (len=in.read(buffer)) != -1) {
            //4,寫數據
            out.write(buffer, 0, len);
        }
        //5,關閉流
        in.close();
        out.close();
    }

    //方式1: 採用基本的流,一次一個字節的方式複製
    private static void method1(String src, String dest) throws IOException {
        //1,指定數據源
        FileInputStream in = new FileInputStream(src);
        //2,指定目的地
        FileOutputStream out = new FileOutputStream(dest);
        //3,讀數據
        int ch = -1;
        while (( ch=in.read()) != -1) {
            //4,寫數據
            out.write(ch);
        }
        //5,關閉流
        in.close();
        out.close();
    }
}
複製代碼

4.2.字符緩衝流

  字符緩衝輸入流 BufferedReader

  字符緩衝輸出流 BufferedWriter

  完成文本數據的高效的寫入與讀取的操做

4.2.1.字符緩衝輸出流BufferedWriter

  將文本寫入字符輸出流,緩衝各個字符,從而提供單個字符、數組和字符串的高效寫入。

  方法:void newLine() 根據當前的系統,寫入一個換行符

/*
 * BufferedWriter 字符緩衝輸出流
 * 方法
 *     public void newLine()寫入一個行分隔符
 * 
 * 需求: 經過緩衝輸出流寫入數據到文件
 * 分析:
 *     1,建立流對象
 *     2,寫數據
 *     3,關閉流
 * 
 */
public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        //建立流
        //基本字符輸出流
        FileWriter fileOut = new FileWriter("file.txt");
        //把基本的流進行包裝
        BufferedWriter out = new BufferedWriter(fileOut);
        //2,寫數據
        for (int i=0; i<5; i++) {
            out.write("hello");
            out.newLine();
        }
        //3,關閉流
        out.close();
    }
}
複製代碼

4.2.2.字符緩衝輸入流BufferedReader

  從字符輸入流中讀取文本,緩衝各個字符,從而實現字符、數組和行的高效讀取。

  方法public String readLine() 讀取一個文本行,包含該行內容的字符串,不包含任何行終止符,若是已到達流末尾,則返回 null

/*
 * BufferedReader 字符緩衝輸入流
 * 
 * 方法:
 *     String readLine() 
 * 需求:從文件中讀取數據,並顯示數據
 */
public class BufferedReaderDemo {
    public static void main(String[] args) throws IOException {
        //1,建立流
        BufferedReader in = new BufferedReader(new FileReader("file.txt"));
        //2,讀數據
        //一次一個字符
        //一次一個字符數組
        //一次讀取文本中一行的字符串內容
        String line = null;
        while( (line = in.readLine()) != null ){
            System.out.println(line);
        }
        
        //3,關閉流
        in.close();
    }
}
複製代碼

4.2.3.使用字符緩衝流完成文本文件的複製

  剛剛咱們學習完了緩衝流,如今咱們就使用字符緩衝流的特有功能,完成文本文件的複製

/*
 * 採用高效的字符緩衝流,完成文本文件的賦值
 * 
 * 數據源: file.txt
 * 目的地: copyFile.txt
 * 
 * 分析:
 *     1,指定數據源, 是數據源中讀數據,採用輸入流
 *     2,指定目的地,是把數據寫入目的地,採用輸出流
 *     3,讀數據
 *     4,寫數據
 *     5,關閉流
 */
public class CopyTextFile {
    public static void main(String[] args) throws IOException {
        //1,指定數據源, 是數據源中讀數據,採用輸入流
        BufferedReader in = new BufferedReader(new FileReader("file.txt"));
        //2,指定目的地,是把數據寫入目的地,採用輸出流
        BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
        //3,讀數據
        String line = null;
        while ( (line = in.readLine()) != null ) {
            //4,寫數據
            out.write(line);
            //寫入換行符號
            out.newLine();
        }
        //5,關閉流
        out.close();
        in.close();
    }
}
複製代碼

5.Properties類

5.1.Properties類介紹

  Properties特色:

    一、Hashtable的子類,map集合中的方法均可以用。

    二、該集合沒有泛型。鍵值都是字符串。

    三、它是一個能夠持久化的屬性集。鍵值能夠存儲到集合中,也能夠存儲到持久化的設備(硬盤、U盤、光盤)上。鍵值的來源也能夠是持久化的設備。

    四、有和流技術相結合的方法。

      a.load(InputStream) 把指定流所對應的文件中的數據,讀取出來,保存到Propertie集合中

      b. load(Reader)

      c. store(OutputStream,commonts)把集合中的數據,保存到指定的流所對應的文件中,參數commonts表明對描述信息

      d.stroe(Writer,comments);

/*
 * 
 * Properties集合,它是惟一一個能與IO流交互的集合
 * 
 * 需求:向Properties集合中添加元素,並遍歷
 * 
 * 方法:
 * public Object setProperty(String key, String value)調用 Hashtable 的方法 put。
 * public Set<String> stringPropertyNames()返回此屬性列表中的鍵集,
 * public String getProperty(String key)用指定的鍵在此屬性列表中搜索屬性
 */
public class PropertiesDemo01 {
    public static void main(String[] args) {
        //建立集合對象
        Properties prop = new Properties();
        //添加元素到集合
        //prop.put(key, value);
        prop.setProperty("周迅", "張學友");
        prop.setProperty("李小璐", "賈乃亮");
        prop.setProperty("楊冪", "劉愷威");
        
        //System.out.println(prop);//測試的使用
        //遍歷集合
        Set<String> keys = prop.stringPropertyNames();
        for (String key : keys) {
            //經過鍵 找值
            //prop.get(key)
            String value = prop.getProperty(key);
            System.out.println(key+"==" +value);
        }
    }
}
複製代碼

將配置文件中的數據存儲到文件中

/**
 * 需求:使用Properties集合,完成把集合內容存儲到IO流所對應文件中的操做
 * 
 * 分析:
 *     1,建立Properties集合
 *     2,添加元素到集合
 *     3,建立流
 *     4,把集合中的數據存儲到流所對應的文件中
 *        store(OutputStream,commonts)把集合中的數據,保存到指定的流所對應的文件中,參數commonts表明對描述信息
 *        stroe(Writer,comments);
 *     5,關閉流
 */
public class PropertiesDemo02 {
    public static void main(String[] args) throws IOException {
        //1,建立Properties集合
        Properties prop = new Properties();
        //2,添加元素到集合
        prop.setProperty("周迅", "張學友");
        prop.setProperty("李小璐", "賈乃亮");
        prop.setProperty("楊冪", "劉愷威");
        
        //3,建立流
        FileWriter out = new FileWriter("prop.properties");
        //4,把集合中的數據存儲到流所對應的文件中
        prop.store(out, "save data");
        //5,關閉流
        out.close();
    }
}
複製代碼

讀取配置文件中的數據,同時更新數據,並保存

/*
 * 需求:從屬性集文件prop.properties 中取出數據,保存到集合中
 * 分析:
 *     1,建立集合
 *     2,建立流對象
 *     3,把流所對應文件中的數據 讀取到集合中
 *        load(InputStream)  把指定流所對應的文件中的數據,讀取出來,保存到Propertie集合中
        load(Reader)  
 *     4,關閉流
 *     5,顯示集合中的數據
 */
public class PropertiesDemo03 {
    public static void main(String[] args) throws IOException {
        //1,建立集合
        Properties prop = new Properties();
        //2,建立流對象
        FileInputStream in = new FileInputStream("prop.properties");
//FileReader in = new FileReader("prop.properties");
        //3,把流所對應文件中的數據 讀取到集合中
        prop.load(in);
        //4,關閉流
        in.close();
        //5,顯示集合中的數據
        System.out.println(prop);
        
    }
複製代碼

注意:使用字符流FileReader就能夠完成文件中文的讀取操做了

6.序列化流與煩序列化流

6.1.對象序列化流

  用於從流中讀取對象的操做流 ObjectInputStream 稱爲 反序列化流

  用於向流中寫入對象的操做流 ObjectOutputStream 稱爲 序列化流

  特色:用於操做對象。

  解決問題:能夠將對象進行序列化和反序列化

  注意:對象序列化必定要實現Serializable接口。爲了給類定義一個serialVersionUID。

  功能:

   ObjectInputStream readObject()

   ObjectOutputStream writeObject()

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        /*
         * 將一個對象存儲到持久化(硬盤)的設備上。
         */
        writeObj();//對象的序列化。
    }
    public static void writeObj() throws IOException {
        //1,明確存儲對象的文件。
        FileOutputStream fos = new FileOutputStream("tempfile\\obj.object");
        //2,給操做文件對象加入寫入對象功能。
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        //3,調用了寫入對象的方法。
        oos.writeObject(new Person("wangcai",20));
        //關閉資源。
        oos.close();
    }
}
複製代碼

6.2.對象反序列化流

  當把一個對象持久化存儲起來以後,須要使用反序列化技術獲取存儲起來的對象。使用此ObjectInputStream對象就能夠完成反序列化動做

public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        readObj();//對象的反序列化。
    }
    public static void readObj() throws IOException, ClassNotFoundException {
        
        //1,定義流對象關聯存儲了對象文件。
        FileInputStream fis = new FileInputStream("tempfile\\obj.object");
        
        //2,創建用於讀取對象的功能對象。
        ObjectInputStream ois = new ObjectInputStream(fis);
        
        Person obj = (Person)ois.readObject();
        
        System.out.println(obj.toString());
        
    }
}
複製代碼

6.3.序列化接口

  當一個對象要能被序列化,這個對象所屬的類必須實現Serializable接口。不然會發生異常NotSerializableException異常。

  同時當反序列化對象時,若是對象所屬的class文件在序列化以後進行的修改,那麼進行反序列化也會發生異常InvalidClassException。發生這個異常的緣由以下:

     該類的序列版本號與從流中讀取的類描述符的版本號不匹配

     該類包含未知數據類型

     該類沒有可訪問的無參數構造方法

  Serializable標記接口。該接口給須要序列化的類,提供了一個序列版本號。serialVersionUID. 該版本號的目的在於驗證序列化的對象和對應類是否版本匹配。

public class Person implements Serializable {

    //給類顯示聲明一個序列版本號。
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    public Person() {
        super();
        
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
複製代碼

7.總結

  • 字節流

   字節輸入流 InputStream

    FileInputStream 操做文件的字節輸入流

    BufferedInputStream高效的字節輸入流

     ObjectInputStream 反序列化流(操做對象的字節輸入流)

   字節輸出流 OutputStram

     FileOutputStream 操做文件的字節輸出流

    BufferedOutputStream 高效的字節輸出流

     ObjectOuputStream 序列化流(操做對象的字節輸出流)

  • 字符流

   字符輸入流 Reader

    FileReader 操做文件的字符輸入流

     BufferedReader 高效的字符輸入流

     InputStreamReader 輸入操做的轉換流(把字節流封裝成字符流)

   字符輸出流 Writer

    FileWriter 操做文件的字符輸出流

     BufferedWriter 高效的字符輸出流

     OutputStreamWriter 輸出操做的轉換流(把字節流封裝成字符流)

              將字符流轉換成字節流去存儲

  • 方法:

  讀數據方法:

    read() 一次讀一個字節或字符的方法

    read(byte[] char[]) 一次讀一個數組數據的方法

    readLine() 一次讀一行字符串的方法(BufferedReader類特有方法)

     readObject() 從流中讀取對象(ObjectInputStream特有方法)

  寫數據方法:

    write(int) 一次寫一個字節或字符到文件中

    write(byte[] char[]) 一次寫一個數組數據到文件中

     write(String) 一次寫一個字符串內容到文件中

     writeObject(Object ) 寫對象到流中(ObjectOutputStream類特有方法)

    newLine() 寫一個換行符號(BufferedWriter類特有方法)

  • 向文件中寫入數據的過程

  1,建立輸出流對象

  2,寫數據到文件

  3,關閉輸出流

  • 從文件中讀數據的過程

  1, 建立輸入流對象

  2, 從文件中讀數據

  3, 關閉輸入流

  • 文件複製的過程

  1, 建立輸入流(數據源)

  2, 建立輸出流(目的地)

  3, 從輸入流中讀數據

  4, 經過輸出流,把數據寫入目的地

  5, 關閉流

  • Properties:Map集合的一種,它是Hashtable集合的子集合,它鍵與值都是String類型,它是惟一能與IO流結合使用的集合

  方法

  load( InputStream in ) 從流所對應的文件中,讀數據到集合中

   load( Reader in ) 從流所對應的文件中,讀數據到集合中

  store( OutputStream out , String message ) 把集合中的數據,寫入到流所對應的文件中

  store( Writer out , String message) 把集合中的數據,寫入到流所對應的文件中

實現文件內容的自動追加

構造方法

   FileOutputStream(File file, boolean append)

   FileOutputStream(String fileName, boolean append)

   FileWriter(File, boolean append)

   FileWriter(String fileName, boolean append)

參考:

java編程思想

黑馬教學視頻

www.cnblogs.com/dz-boss/p/1…

相關文章
相關標籤/搜索