天天看點

位元組流、字元流1、IO概述2、位元組流3、字元流(字元輸出流有内置數組)4、IO異常的處理5、屬性的集合,簡稱屬性集

主要内容

  • IO流
  • 位元組流
  • 字元流
  • 異常處理
  • Properties

學習目标

  • 能夠說出IO流的分類和功能
  • 能夠使用位元組輸出流寫出資料到檔案
  • 能夠使用位元組輸入流讀取資料到程式
  • 能夠了解讀取資料read(byte[])方法
  • 能夠使用位元組流完成檔案的複制
  • 能夠使用FileReader讀資料
  • 能夠使用FileReader讀資料一次一個字元數組
  • 能夠使用FileWirter寫資料到檔案
  • 能夠說出FileWriter中關閉和重新整理方法的差別
  • 能夠使用FileWriter寫資料的5個方法
  • 能夠使用FileWriter寫資料實作換行和追加寫
  • 能夠使用Properties的load方法加載檔案中的配置資訊

1、IO概述

1.1 IO----用來傳輸資料的方式

生活中,你肯定經曆過這樣的場景。當你編輯一個文本檔案,忘記了

ctrl+s

儲存,然後斷電了,可能檔案就白白編輯了。當你電腦上插入一個U盤,可以把一個視訊,拷貝到你的電腦硬碟裡。那麼資料都是在哪些裝置上的呢?鍵盤、記憶體、硬碟、外接裝置等等。

我們把這種資料的傳輸,可以看做是一種資料的流動,按照流動的方向,以記憶體為基準,分為

輸入input

輸出output

,即流向記憶體是輸入流,流出記憶體的是輸出流。

Java中I/O操作,主要是指使用

java.io

包下的内容,進行輸入、輸出操作。輸入也叫做讀取資料,輸出也叫做作寫出資料。

1.2 IO的分類(能夠說出IO流的分類和功能)

  • 按照資料的流向分為:輸入流和輸出流
    • 輸入流 :把資料從

      其他裝置

      上讀取到

      記憶體

      中的流。 //功能,讀取資料
    • 輸出流 :把資料從

      記憶體

      中寫出到

      其他裝置

      上的流。 //功能,把資料寫出到其他地方
  • 按照資料的類型分為:位元組流和字元流
    • 位元組流 :以位元組為機關,讀寫資料的流。
    • 字元流 :以字元為機關,讀寫資料的流。 //字元流=位元組流+碼表

1.3 IO的流向說明圖解
位元組流、字元流1、IO概述2、位元組流3、字元流(字元輸出流有内置數組)4、IO異常的處理5、屬性的集合,簡稱屬性集

1.4 頂級父類們,都是抽象類,用他們的子類來完成io流讀寫操作(選擇題)

輸入流 輸出流
位元組流

位元組輸入流

InputStream

位元組輸出流

OutputStream

字元流

字元輸入流

Reader

字元輸出流

Writer

  • 注意:一般情況下,看到類以stream結尾是位元組流,以er結尾的是字元流!!!

2、位元組流

2.1 一切皆為位元組

一切檔案資料(文本、圖檔、視訊等)在存儲時,都是以二進制數字的形式儲存的,是一個一個位元組,那麼傳輸時一樣如此。
  • 是以,位元組流可以傳輸任意檔案資料。
在操作流的時候,我們要時刻明确,無論使用什麼樣的流對象,底層傳輸的,始終為二進制資料!!!

2.2 位元組輸出流【OutputStream】

java.io.OutputStream

抽象類是表示位元組輸出流的所有類的超類,将指定的位元組資訊寫出到目的地。它定義了位元組輸出流的基本共性功能(方法)。

  • public void close()

    : 關閉此輸出流,并釋放與此流相關聯的,任何系統資源。 内置緩沖區重新整理
  • public void flush()

    : 重新整理此輸出流,并強制任何緩沖的輸出位元組被寫出。
  • public void write(byte[] b)

    : 将 b.length位元組從指定的位元組數組寫入此輸出流。
  • public void write(byte[] b, int off, int len)

    : 從指定的位元組數組寫入 len位元組,從偏移量 off開始輸出到此輸出流。
  • public abstract void write(int b)

    : 将指定的位元組寫到輸出流。97,碼表翻譯a,打開檔案是a
小貼士:close方法,當完成流的操作時,推薦調用此方法,來釋放系統資源。

2.3 FileOutputStream類

OutputStream

有很多子類,從最簡單的一個子類開始。

java.io.FileOutputStream

類是檔案輸出流,把資料寫出到檔案中。

2.3.1 構造方法

  • public FileOutputStream(File file)

    :建立檔案輸出流,以寫入由指定的 File對象表示的檔案。
  • public FileOutputStream(String name)

    : 建立檔案輸出流,以指定的名稱寫入檔案。

當你建立一個輸出流對象寫資料到檔案中時,必須傳入一個檔案路徑。輸出流的構造方法,如果沒有這個檔案,會建立該檔案。如果有這個檔案,會清空這個檔案的資料**(不想清空,在構造方法()裡面加個逗号和true表示追加内容,不清空原來的資料)**。

  • 構造舉例,代碼如下:
public class FileOutputStreamConstructor throws IOException {
    public static void main(String[] args) {
   	 	// 使用File對象建立流對象
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
      
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("b.txt");
    }
}
           

2.3.2 寫出位元組資料,(能夠使用位元組輸出流寫出資料到檔案)

  1. 寫出位元組:

    write(int b)

    方法,每次可以寫出一個位元組資料,代碼使用示範:
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("fos.txt");
        
      	// 寫出資料
      	fos.write(97); // 寫出第1個位元組
      	fos.write(98); // 寫出第2個位元組
      	fos.write(99); // 寫出第3個位元組
        
      	// 關閉資源
        fos.close();
    }
}
輸出結果://寫過去的是97,經過碼表翻譯成a,97對應的字元是a,這個在基礎班,我們已經學習過了!!!
abc
           
小貼士:
  1. 雖然參數為int類型四個位元組,但是隻會保留一個位元組的資訊寫出。
  2. 流操作完畢後,推薦釋放系統資源,調用close方法,千萬記得。
  1. 寫出位元組數組:

    write(byte[] b)

    ,每次可以寫出數組中的資料,代碼使用示範:
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("fos.txt");    
        
      	// 字元串轉換為位元組數組
      	byte[] b = "黑馬程式員".getBytes();
      	// 寫出位元組數組資料
      	fos.write(b);
        
      	// 關閉資源
        fos.close();
    }
}
輸出結果:
黑馬程式員
           
  1. 寫出指定長度位元組數組:

    write(byte[] b, int off, int len)

    ,每次寫出從off索引開始,len個位元組,代碼使用示範:
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
        
      	// 字元串轉換為位元組數組
      	byte[] b = "abcde".getBytes();
		// 寫出從索引2開始,2個位元組。索引2是c,兩個位元組,也就是cd。
        fos.write(b,2,2);
        
      	// 關閉資源
        fos.close();
    }
}
輸出結果:
cd
           

2.3.3 資料追加續寫

經過以上的示範,每次程式運作,建立輸出流對象,都會清空目标檔案中的資料。如何保留目标檔案中資料,還能繼續添加新資料呢?

  • public FileOutputStream(File file, boolean append)

    : 建立檔案輸出流以寫入由指定的 File對象表示的檔案。
  • public FileOutputStream(String name, boolean append)

    : 建立檔案輸出流以指定的名稱寫入檔案。

這兩個構造方法,參數中都需要傳入一個boolean類型的值,

true

表示追加資料,

false

表示清空原有資料。這樣建立的輸出流對象,就可以指定是否追加續寫了,代碼使用示範:

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("fos.txt",true);   
        
      	// 字元串轉換為位元組數組
      	byte[] b = "abcde".getBytes();
		// 寫出從索引2開始,2個位元組。索引2是c,兩個位元組,也就是cd。
        fos.write(b);
        
      	// 關閉資源
        fos.close();
    }
}
檔案操作前:cd
檔案操作後:cdabcde
           

2.3.4 寫出換行

Windows系統裡,換行符号是

\r\n

。代碼使用示範:

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileOutputStream fos = new FileOutputStream("fos.txt");  
        
      	// 定義位元組數組
      	byte[] words = {97,98,99,100,101};
      	// 周遊數組
        for (int i = 0; i < words.length; i++) {
          	// 寫出一個位元組
            fos.write(words[i]);
          	// 寫出一個換行, 換行符号轉成數組寫出
            fos.write("\r\n".getBytes());
        }
        
      	// 關閉資源
        fos.close();
    }
}

輸出結果:
a
b
c
d
e
           
  • 回車符

    \r

    和換行符

    \n

    • 回車符:回到一行的開頭(return)。
    • 換行符:下一行(newline)。
  • 系統中的換行:
    • Windows系統裡,每行結尾是

      回車+換行

      ,即

      \r\n

    • Unix系統裡,每行結尾隻有

      換行

      ,即

      \n

    • Mac系統裡,每行結尾是

      回車

      ,即

      \r

2.4 位元組輸入流【InputStream】

java.io.InputStream

抽象類是表示位元組輸入流的所有類的超類,可以讀取位元組資訊到記憶體中。它定義了位元組輸入流的基本共性功能方法。

  • public void close()

    :關閉此輸入流,并釋放與此流相關聯的任何系統資源。
  • public abstract int read()

    : 從輸入流讀取資料的下一個位元組。
  • public int read(byte[] b)

    : 從輸入流中讀取一些位元組數,并将它們存儲到位元組數組 b中 。

小貼士:

close方法,當完成流的操作時,調用推薦此方法,釋放系統資源。

2.5 FileInputStream類

java.io.FileInputStream

類是檔案輸入流,用來讀取檔案的。

2.5.1 構造方法

  • FileInputStream(File file)

    : 通過打開與實際檔案的連接配接來建立一個 FileInputStream ,該檔案由檔案系統中的 File對象 file命名。
  • FileInputStream(String name)

    : 通過打開與實際檔案的連接配接來建立一個 FileInputStream ,該檔案由檔案系統中的路徑名 name命名。

當建立一個輸入流對象時,必須傳入一個檔案路徑。該路徑下,如果沒有該檔案,會抛出

FileNotFoundException

  • 構造舉例,代碼如下:
public class FileInputStreamConstructor throws IOException{
    public static void main(String[] args) {
   	 	// 使用File對象建立流對象
        File file = new File("a.txt");
        FileInputStream fos = new FileInputStream(file);
      
        // 使用檔案名稱建立流對象
        FileInputStream fos = new FileInputStream("b.txt");
    }
}
           

2.5.2 讀取位元組資料

  1. 讀取位元組:

    read

    方法,每次可以讀取一個位元組的資料,提升為int類型,如果讀取到檔案末尾,則傳回

    -1

    表示,代碼使用示範:
public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用檔案名稱建立流對象
       	FileInputStream fis = new FileInputStream("read.txt");
        
      	// 讀取資料,傳回一個位元組
        int read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        
      	// 讀取到末尾,傳回-1
       	read = fis.read();
        System.out.println( read);
        
		// 關閉資源
        fis.close();
    }
}
輸出結果:
a
b
c
d
e
-1
           

循環改進讀取方式,代碼使用示範:(能夠使用位元組輸入流讀取資料到程式)

public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用檔案名稱建立流對象
       	FileInputStream fis = new FileInputStream("read.txt");
        
      	// 定義變量,儲存資料
        int b ;
        // 循環讀取
        while ((b = fis.read())!=-1) {
            System.out.println((char)b);
        }
        
		// 關閉資源
        fis.close();
    }
}
輸出結果:
a
b
c
d
e
           
  1. 使用位元組數組讀取:

    read(byte[] b)

    ,每次讀取b的長度個位元組到數組中,方法的傳回值,傳回讀取到的有效位元組個數,讀取到檔案末尾時,傳回

    -1

    表示,代碼使用表示示範:
public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用檔案名稱建立流對象.
       	FileInputStream fis = new FileInputStream("read.txt"); // 檔案中為abcde
        
      	// 定義變量,作為有效個數
        int len ;
        // 定義位元組數組,作為裝位元組資料的容器   
        byte[] b = new byte[2];
        // 循環讀取
        while (( len= fis.read(b))!=-1) {
           	// 每次讀取後,把數組變成字元串列印
            System.out.println(new String(b));
        }
        
		// 關閉資源
        fis.close();
    }
}

輸出結果:
ab
cd
ed
           

錯誤資料

d

,是由于最後一次讀取時,隻讀取一個位元組

e

,數組中,上次讀取的資料沒有被完全替換,是以要通過

len

,擷取有效的位元組,代碼使用示範:

public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用檔案名稱建立流對象.
       	FileInputStream fis = new FileInputStream("read.txt"); // 檔案中為abcde
        
      	// 定義變量,作為有效個數
        int len ;
        // 定義位元組數組,作為裝位元組資料的容器   
        byte[] b = new byte[2];
        // 循環讀取
        while (( len= fis.read(b))!=-1) {
           	// 每次讀取後,把數組的有效位元組部分,變成字元串列印
            System.out.println(new String(b,0,len));//  len 每次讀取的有效位元組個數
        }
        
		// 關閉資源
        fis.close();
    }
}

輸出結果:
ab
cd
e
           

小貼士:

使用數組讀取,每次讀取多個位元組,減少了系統間的IO操作次數,進而提高了讀寫的效率,建議開發中使用。

超級總結:不會讀,記下面的!!!

位元組輸入流FileInputStream讀一個位元組read()和讀一個位元組數組read(byte[] arr)方法,

有數組讀取到的内容存到數組,方法的傳回值表示讀取到的有效位元組個數,

沒數組讀取到的内容存到read方法的傳回值,

但是隻要讀不到都傳回-1,就可以定義變量接收read方法的傳回值,循環指派判斷不等于-1就可以一直讀

套路:

int ch;

while(()!=-1){//()當成一個整體,不要漏掉裡面的()括号!!!記憶!!!

}

位元組輸入流一個讀一個位元組和一個讀一個位元組數組的代碼總結如下:(能夠了解讀取資料read(byte[])方法)

//file,讀檔案,跟檔案相關,位元組輸入流一個讀一個位元組數組
        FileInputStream fis = new FileInputStream("day09\\a.txt");
        int ch;

        byte[] arr = new byte[2];
        while ((ch=fis.read(arr))!=-1) {//97
            System.out.print(new String(arr,0,ch));//abc,把讀取到數組的有效位元組變成字元串
        }

        fis.close();

//		 file,讀檔案,跟檔案相關,位元組輸入流一個讀一個位元組
//        int ch;
//        while ((ch=fis.read())!=-1) {
//            System.out.print((char)ch);//abc
//        }
//
//        fis.close();
           

2.6 位元組流練習:複制,又叫拷貝,檔案的讀和寫就是拷貝,簡單

2.6.1 複制原理圖解

位元組流、字元流1、IO概述2、位元組流3、字元流(字元輸出流有内置數組)4、IO異常的處理5、屬性的集合,簡稱屬性集

2.6.2 案例實作

複制圖檔檔案,代碼使用示範:(能夠使用位元組流完成檔案的複制)

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Test03 {
    public static void main(String[] args) throws Exception {
        //複制,又叫拷貝,檔案的讀和寫就是拷貝,簡單a.txt//abc979899
        //一次讀寫一個位元組的拷貝,file
//        FileInputStream fis = new FileInputStream("day09\\a.txt");
//        FileOutputStream fos = new FileOutputStream("day09\\b.txt");//輸出流構造方法,沒有檔案建立
//
//        int ch;
//        while ((ch=fis.read())!=-1) {
//            //System.out.print(ch);/979899沒有數組讀到ch裡面存起來
//            fos.write(ch);
//        }
//
//        fis.close();
//        fos.close();

        //一次讀寫一個位元組數組的拷貝
        FileInputStream fis = new FileInputStream("day09\\a.txt");
        FileOutputStream fos = new FileOutputStream("day09\\c.txt");//輸出流構造方法,沒有檔案建立

        int ch;
        byte[] arr = new byte[2];
        while ((ch=fis.read(arr))!=-1) {
            fos.write(arr, 0, ch);
        }

        fis.close();
        fos.close();
    }
}
           
小貼士:流的關閉原則:先開後關,後開先關。

3、字元流(字元輸出流有内置數組)

當使用位元組流讀取文本檔案時,可能會有一個小問題。就是遇到中文字元時,可能不會顯示完整的字元,那是因為一個中文字元,可能占用多個位元組存儲。

是以Java提供一些字元流類,以字元為機關讀寫資料,專門用于處理文本檔案,無法拷貝圖檔視訊之類的非文本檔案

3.1 字元輸入流【Reader】

java.io.Reader

抽象類是表示用于讀取字元流的所有類的超類,可以讀取位元組資訊到記憶體中。它定義了位元組輸入流的基本共性功能方法。

  • public void close()

    :關閉此流,并釋放與此流相關聯的任何系統資源。
  • public int read()

    : 從輸入流讀取一個字元。
  • public int read(char[] cbuf)

    : 從輸入流中讀取一些字元,并将它們存儲到字元數組 cbuf中 。

3.2 FileReader類

java.io.FileReader

類是讀取字元檔案的便利類

構造方法

  • FileReader(File file)

    : 建立一個新的 FileReader ,給定要讀取的File對象。
  • FileReader(String fileName)

    : 建立一個新的 FileReader ,給定要讀取的檔案的名稱。

當你建立一個流對象時,必須傳入一個檔案路徑。類似于FileInputStream 。

  • 構造舉例,代碼如下:
public class FileReaderConstructor throws IOException{
    public static void main(String[] args) {
   	 	// 使用File對象建立流對象
        File file = new File("a.txt");
        FileReader fr = new FileReader(file);
      
        // 使用檔案名稱建立流對象
        FileReader fr = new FileReader("b.txt");
    }
}
           

讀取字元資料,(能夠使用FileReader讀資料)

  1. 讀取字元:

    read

    方法,每次可以讀取一個字元的資料,提升為int類型,讀取到檔案末尾,傳回

    -1

    ,循環讀取,代碼使用示範:
public class FRRead {
    public static void main(String[] args) throws IOException {
      	// 使用檔案名稱建立流對象
       	FileReader fr = new FileReader("read.txt");
        
      	// 定義變量,儲存資料
        int b ;
        // 循環讀取
        while ((b = fr.read())!=-1) {
            System.out.println((char)b);
        }
        
		// 關閉資源
        fr.close();
    }
}
輸出結果:
黑
馬
程
序
員
           
小貼士:雖然讀取了一個字元,但是會自動提升為int類型。
  1. 使用字元數組讀取:

    read(char[] cbuf)

    ,每次讀取b的長度個字元到數組中,傳回讀取到的有效字元個數,讀取到末尾時,傳回

    -1

    ,代碼使用示範:
public class FRRead {
    public static void main(String[] args) throws IOException {
      	// 使用檔案名稱建立流對象
       	FileReader fr = new FileReader("read.txt");
        
      	// 定義變量,儲存有效字元個數
        int len ;
        // 定義字元數組,作為裝字元資料的容器
         char[] cbuf = new char[2];
        // 循環讀取
        while ((len = fr.read(cbuf))!=-1) {
            System.out.println(new String(cbuf));
        }
        
		// 關閉資源
        fr.close();
    }
}
輸出結果:
黑馬
程式
員序
           

擷取有效的字元改進,代碼使用示範:(能夠使用FileReader讀資料一次一個字元數組)

public class FISRead {
    public static void main(String[] args) throws IOException {
      	// 使用檔案名稱建立流對象
       	FileReader fr = new FileReader("read.txt");
        
      	// 定義變量,儲存有效字元個數
        int len ;
        // 定義字元數組,作為裝字元資料的容器
        char[] cbuf = new char[2];
        // 循環讀取
        while ((len = fr.read(cbuf))!=-1) {
            System.out.println(new String(cbuf,0,len));
        }
        
    	// 關閉資源
        fr.close();
    }
}

輸出結果:
黑馬
程式
員
           

3.3 字元輸出流【Writer】

總結:

字元輸出流有内置數組,先寫到内置數組緩沖區,滿了重新整理到檔案,

不滿殘留内置數組,檔案沒有,

要手動調用輸出流的close方法,關閉流之前,重新整理内置數組資料到檔案中

java.io.Writer

抽象類是表示用于寫出字元流的所有類的超類,将指定的字元資訊寫出到目的地。它定義了位元組輸出流的基本共性功能方法。

  • public abstract void close()

    :關閉此輸出流,并釋放與此流相關聯的任何系統資源。
  • public abstract void flush()

    :重新整理此輸出流.并強制任何緩沖的輸出字元被寫出。
  • public void write(int c)

    :寫出一個字元。
  • public void write(char[] cbuf)

    :将 b.length字元從指定的字元數組,寫出此輸出流。
  • public abstract void write(char[] b, int off, int len)

    :從指定的字元數組寫出 len字元,從偏移量 off開始輸出到此輸出流。
  • public void write(String str)

    :寫出一個字元串。//多了寫直接寫字元串,位元組流把字元串變成位元組數組寫過去,調用getBytes()得到位元組數組

3.4 FileWriter類

java.io.FileWriter

類是寫出字元到檔案的便利類。構造時使用系統預設的字元編碼和預設字元緩沖區。

構造方法

  • FileWriter(File file)

    : 建立一個新的 FileWriter,給定要讀取的File對象。
  • FileWriter(String fileName)

    : 建立一個新的 FileWriter,給定要讀取的檔案的名稱。

當你建立一個流出對象時,必須傳入一個檔案路徑,類似于FileOutputStream。構造方法沒有檔案幫你建立,有檔案清空,不想清空,追加,逗号,true表示追加,不清空,在後面增加

  • 構造舉例,代碼如下:
public class FileWriterConstructor {
    public static void main(String[] args) throws IOException {
   	 	// 使用File對象建立流對象
        File file = new File("a.txt");
        FileWriter fw = new FileWriter(file);
      
        // 使用檔案名稱建立流對象
        FileWriter fw = new FileWriter("b.txt");
    }
}
           

寫出資料,(能夠使用FileWirter寫資料到檔案)

寫出字元:

write(int b)

方法,每次可以寫出一個字元資料,代碼使用示範:

public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileWriter fw = new FileWriter("fw.txt");   
        
      	// 寫出資料
      	fw.write(97); // 寫出第1個字元
      	fw.write('b'); // 寫出第2個字元
      	fw.write('C'); // 寫出第3個字元
      	fw.write(30000); // 寫出第4個字元,中文編碼表中30000對應一個漢字。
      
      	/*
        【注意】關閉資源時,與FileOutputStream不同。
      	 如果不關閉,資料隻是儲存到緩沖區數組,并未儲存到檔案。
        */
        // fw.close();
    }
}
輸出結果:
abC田
           
小貼士:
  1. 雖然參數為int類型四個位元組,但是隻會保留一個字元的資訊寫出。
  2. 未調用close方法,資料隻是儲存到了緩沖區數組,并未寫出到檔案中。

關閉和重新整理,(能夠說出FileWriter中關閉和重新整理方法的差別)

因為内置緩沖區數組的原因,如果不關閉輸出流,無法寫出字元到檔案中。但是關閉的流對象,是無法繼續寫出資料的。如果我們既想寫出資料,又想繼續使用流,就需要

flush

方法了。

  • flush

    :重新整理緩沖區,流對象可以繼續使用。
  • close

    :關閉流,釋放系統資源。關閉前會重新整理緩沖區。

代碼使用示範:

public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileWriter fw = new FileWriter("fw.txt");
        // 寫出資料,通過flush
        fw.write('刷'); // 寫出第1個字元
        fw.flush();
        fw.write('新'); // 繼續寫出第2個字元,寫出成功
        fw.flush();
      
      	// 寫出資料,通過close
        fw.write('關'); // 寫出第1個字元
        fw.close();
        fw.write('閉'); // 繼續寫出第2個字元,【報錯】java.io.IOException: Stream closed
        fw.close();
    }
}
           
小貼士:即便是flush方法寫出了資料,操作的最後還是建議要調用close方法,來釋放系統資源。

寫出其他資料,(能夠使用FileWriter寫資料的5個方法)

  1. 寫出字元數組 :

    write(char[] cbuf)

    write(char[] cbuf, int off, int len)

    ,每次可以寫出字元數組中的資料,用法類似FileOutputStream,代碼使用示範:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileWriter fw = new FileWriter("fw.txt"); 
        
      	// 字元串轉換為位元組數組
      	char[] chars = "黑馬程式員".toCharArray();
      
      	// 寫出字元數組
      	fw.write(chars); // 黑馬程式員
        
		// 寫出從索引2開始,2個字元。索引2是'程',兩個字元,也就是'程式'。
        fw.write(b,2,2); // 程式
      
      	// 關閉資源
        fos.close();
    }
}
           
  1. 寫出字元串:

    write(String str)

    write(String str, int off, int len)

    ,每次可以寫出字元串中的資料,更為友善,代碼使用示範:
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象
        FileWriter fw = new FileWriter("fw.txt");     
      	// 字元串
      	String msg = "黑馬程式員";
      
      	// 寫出字元數組
      	fw.write(msg); //黑馬程式員
      
		// 寫出從索引2開始,2個字元。索引2是'程',兩個字元,也就是'程式'。
        fw.write(msg,2,2);	// 程式
      	
        // 關閉資源
        fos.close();
    }
}
           
  1. 追加和換行:操作類似于FileOutputStream。(能夠使用FileWriter寫資料實作換行和追加寫)
public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用檔案名稱建立流對象,可以追加續寫資料
        FileWriter fw = new FileWriter("fw.txt",true); 
        
      	// 寫出字元串
        fw.write("黑馬");
      	// 寫出換行
      	fw.write("\r\n");
      	// 寫出字元串
  		fw.write("程式員");
        
      	// 關閉資源
        fw.close();
    }
}
輸出結果:
黑馬
程式員
           
小貼士:字元流,隻能操作文本檔案,不能操作圖檔,視訊等非文本檔案。其他圖檔視訊音頻用位元組流,拷貝,秒殺,啥都可以!!!

字元流拷貝(文本,不包括圖檔音頻視訊),即檔案的讀和寫

//字元輸入流跟位元組輸入流用法幾乎一樣,隻不過把位元組換成字元
//字元輸出流,跟位元組輸出流不一樣的地方,在于字元輸出流有内置數組,先寫到内置數組緩沖區,滿了重新整理檔案,不滿殘留
//内置數組,檔案沒有,要手動調用輸出流的close方法,關閉流之前,重新整理内置數組資料到檔案中
 //file,一次讀寫一個字元的拷貝
        FileReader fr = new FileReader("day09//a.txt");
        FileWriter fw = new FileWriter("day09//f.txt");//沒有檔案建立,輸出流内置數組

        int ch;
        while ((ch=fr.read())!=-1) {
//            System.out.print((char)ch);//你好你好啊
            fw.write(ch);
        }

        fr.close();
        fw.close();//關閉,重新整理,數組,檔案

        //一次讀寫一個字元的拷貝
        FileReader fr = new FileReader("day09//a.txt");
        FileWriter fw = new FileWriter("day09//g.txt");//沒有檔案建立,輸出流内置數組

        int ch;
        char[] arr = new char[2];
        while ((ch=fr.read(arr))!=-1) {
//            System.out.print((char)ch);//你好你好啊
            fw.write(arr,0,ch);
        }

        fr.close();
        fw.close();//關閉,重新整理,數組,檔案
           

4、IO異常的處理

JDK7前處理

之前的入門練習,我們一直把異常抛出,而實際開發中一般并不推薦這樣處理,大多數希望後續代碼繼續執行,建議使用

try...catch...finally

代碼塊,處理異常部分,代碼使用示範:

public class HandleException1 {
    public static void main(String[] args) {
      	// 聲明變量
        FileWriter fw = null;
        try {
            //建立流對象
            fw = new FileWriter("fw.txt");
            // 寫出資料
            fw.write("黑馬程式員"); //黑馬程式員
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {//防止上面出現異常沒有給fw指派,調用close方法出現空指針異常
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    }
}
           

JDK7的處理

還可以使用JDK7優化後的

try-with-resource

語句,該語句確定了每個資源,在語句結束時關閉。所謂的資源(resource)是指在程式完成後,必須關閉的流對象。寫在()裡面的流對象對應的類都實作了自動關閉接口AutoCloseable

格式:

try (建立流對象語句,如果多個,使用';'隔開) {
	// 讀寫資料
} catch (IOException e) {
	e.printStackTrace();
}
           

代碼使用示範:

public class HandleException2 {
    public static void main(String[] args) {
      	// 建立流對象
        try ( FileWriter fw = new FileWriter("fw.txt"); ) {
            // 寫出資料
            fw.write("黑馬程式員"); //黑馬程式員
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
           

JDK9的改進(了解内容,看看就好)

JDK9中

try-with-resource

的改進,對于引入對象的方式,支援的更加簡潔。被引入的對象,同樣可以自動關閉,無需手動close,我們來了解一下格式。

改進前格式:

// 被final修飾的對象
final Resource resource1 = new Resource("resource1");
// 普通對象
Resource resource2 = new Resource("resource2");

// 引入方式:建立新的變量儲存
try (Resource r1 = resource1;
     Resource r2 = resource2) {
     // 使用對象
}
           

改進後格式:

// 被final修飾的對象
final Resource resource1 = new Resource("resource1");
// 普通對象
Resource resource2 = new Resource("resource2");

// 引入方式:直接引入
try (resource1; resource2) {
     // 使用對象
}
           

改進後,代碼使用示範:

public class TryDemo {
    public static void main(String[] args) throws IOException {
       	// 建立流對象
        final  FileReader fr  = new FileReader("in.txt");
        FileWriter fw = new FileWriter("out.txt");
       	// 引入到try中
        try (fr; fw) {
          	// 定義變量
            int b;
          	// 讀取資料
          	while ((b = fr.read())!=-1) {
            	// 寫出資料
            	fw.write(b);
          	}
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
           

5、屬性的集合,簡稱屬性集

5.1 概述,

Properties

類除了原來雙列集合的功能,還表示了一個持久的屬性集,屬性清單中每個鍵及其對應值都是一個字元串 ;

Properties

可儲存在流(寫)中或從流中加載(讀)

java.util.Properties

繼承于

Hashtable

,來表示一個持久的屬性集。它使用鍵值結構存儲資料,每個鍵及其對應值都是一個字元串。該類也被許多Java類使用,比如擷取系統屬性時,

System.getProperties

方法就是傳回一個

Properties

對象。

5.2 Properties類,雙列集合put方法

Properties

類表示了一個持久的屬性集合(屬性清單中每個鍵及其對應值都是一個字元串),

Properties

可儲存在流中store,或從流中加載load,Properties類,建立對象,調用方法,簡單

構造方法

  • public Properties()

    :建立一個空的屬性清單。

基本的存儲方法

  • public Object setProperty(String key, String value)

    : 儲存一對屬性。
  • public String getProperty(String key)

    :使用此屬性清單中指定的鍵搜尋屬性值。
  • public Set<String> stringPropertyNames()

    :所有鍵的名稱的集合。
public class ProDemo {
    public static void main(String[] args) throws FileNotFoundException {
        // 建立屬性集對象
        Properties properties = new Properties();
        // 添加鍵值對元素
        properties.setProperty("filename", "a.txt");
        properties.setProperty("length", "209385038");
        properties.setProperty("location", "D:\\a.txt");
        // 列印屬性集對象
        System.out.println(properties);
        // 通過鍵,擷取屬性值
        System.out.println(properties.getProperty("filename"));
        System.out.println(properties.getProperty("length"));
        System.out.println(properties.getProperty("location"));

        // 周遊屬性集,擷取所有鍵的集合
        Set<String> strings = properties.stringPropertyNames();
        // 列印鍵值對
        for (String key : strings ) {
          	System.out.println(key+" -- "+properties.getProperty(key));
        }
    }
}
輸出結果:
{filename=a.txt, length=209385038, location=D:\a.txt}
a.txt
209385038
D:\a.txt
filename -- a.txt
length -- 209385038
location -- D:\a.txt
           

與流相關的方法,(能夠使用Properties的load方法加載檔案中的配置資訊)

  • public void load(InputStream inStream)

    : 從位元組輸入流中讀取關聯的檔案到集合中,一般存儲鍵值對。

參數中使用了位元組輸入流,通過流對象,可以關聯到某檔案上,這樣就能夠加載文本中的資料了。文本資料格式:

filename=a.txt
length=209385038
location=D:\a.txt
           

加載代碼示範:

public class ProDemo2 {
    public static void main(String[] args) throws FileNotFoundException {
        // 建立屬性集對象
        Properties pro = new Properties();
        // 加載文本中資訊到屬性集
        pro.load(new FileInputStream("read.txt"));
        // 周遊集合并列印
        Set<String> strings = pro.stringPropertyNames();
        for (String key : strings ) {
          	System.out.println(key+" -- "+pro.getProperty(key));
        }
     }
}
輸出結果:
filename -- a.txt
length -- 209385038
location -- D:\a.txt
           

課堂示範代碼如下↓

import java.io.FileInputStream;
import java.util.Properties;
public class Test09 {
    public static void main(String[] args) throws Exception {
        //Properties類,雙列集合put方法
//        Properties p = new Properties();//p,沒有泛型<>,出現比較早
//        p.put("xx", 123);//雙列集合啥都可以添加,沒有限定元素的資料類型
        //HashMap替代雙列集合功能,特有的功能

        //Properties 類表示了一個持久的屬性的集合,屬性集合中每個鍵及其對應值都是一個字元串<String>
        Properties p = new Properties();
       // p.setProperty("password", "123");//字元串,屬性,底層就put的字元串
//        String value = p.getProperty("password");//底層就是get(key),通過鍵得到值
//        System.out.println(value);//123
//        System.out.println(p);//{},{password=123}
//
//        //stringPropertyNames,鍵的集合,keySet();
//        Set<String> strings = p.stringPropertyNames();
//        for (String s : strings) {
//            System.out.println(s);//password
//        }

        //Properties可儲存方法在io流中或從流中加載方法
//        System.out.println(p);//{password=123}
        //FileOutputStream fos = new FileOutputStream("day09\\data.txt");//沒有檔案建立
        //p.store(fos, null);//把p裡面的内容通過輸出流寫到關聯的檔案data.txt;寫

        //流中加載方法,讀取
        FileInputStream fis = new FileInputStream("day09\\data.txt");
        p.load(fis);//通過輸入流讀取關聯的檔案,data.txt檔案記憶體,存到p裡面去
        System.out.println(p);//{}
        
        //或從流中加載(讀)↓
        //把東西存到記憶體,加載到記憶體↓
        //file
        //FileInputStream fis = new FileInputStream("day09\\data.txt");
        //FileInputStream fis = new FileInputStream("day09\\data.properties");
        //為了快速讀取配置檔案的内容建議配置檔案放到src檔案夾,A.class用位元組碼檔案的類加載器快速讀取
        //能夠使用Properties的load方法加載檔案中的配置資訊,重點↓
        Properties p = new Properties();//記憶體中屬性配置檔案
        InputStream fis = Test08.class.getClassLoader().getResourceAsStream("data.properties");//.var,src檔案夾的檔案,.class哪裡不會點哪裡

        p.load(fis);//通過fis輸入流讀取檔案裡面内容到p記憶體中,把硬碟中的配置檔案的内容轉移(加載)到記憶體中的配置檔案p裡面
        fis.close();

        //System.out.println(p);//{},{fbb=lic}
        //String value = p.getProperty("fbb");
        //System.out.println(value);
        System.out.println(p.getProperty("fbb"));//lic,lic2
    }
}