JAVA IO之字節流-OutputStream-InputStream-FileOutputStream-FileInputStream

1. 一切皆爲字節

所有文件數據(文本、圖片、視頻等)在存儲時,都是以二進制數字的形式保存,都是一個一個的字節,那麼傳輸時一樣如此。所以,字節流可以傳輸任意文件數據。在操作流的時候,我們要時刻明確,無論使用什麼樣的流對象,底層傳輸的始終爲二進制數據。

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) :將指定的字節輸出流。

小貼士:

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

3. FileOutputStream類

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

java.io.FileOutputStream類是文件輸出流,用於將數據寫出到文件。

構造方法

  • public FileOutputStream(File file):創建文件輸出流以寫入由指定的 File對象表示的文件。
  • public FileOutputStream(String name): 創建文件輸出流以指定的名稱寫入文件。

當你創建一個流對象時,必須傳入一個文件路徑。該路徑下,如果沒有這個文件,會創建該文件。如果有這個文件,會清空這個文件的數據。

  • 構造舉例,代碼如下:
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");
    }
}

寫出字節數據

  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();
    }
}
輸出結果:
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

數據追加續寫

經過以上的演示,每次程序運行,創建輸出流對象,都會清空目標文件中的數據。如何保留目標文件中數據,還能繼續添加新數據呢?

  • 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

寫出換行

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。從 Mac OS X開始與Linux統一。

4. 字節輸入流【InputStream】

java.io.InputStream抽象類是表示字節輸入流的所有類的超類,可以讀取字節信息到內存中。它定義了字節輸入流的基本共性功能方法。

  • public void close() :關閉此輸入流並釋放與此流相關聯的任何系統資源。
  • public abstract int read(): 從輸入流讀取數據的下一個字節。
  • public int read(byte[] b): 從輸入流中讀取一些字節數,並將它們存儲到字節數組 b中 。

小貼士:

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

5. FileInputStream類

java.io.FileInputStream類是文件輸入流,從文件中讀取字節。

構造方法

  • 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");
    }
}

讀取字節數據

  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. 雖然讀取了一個字節,但是會自動提升爲int類型。
  2. 流操作完畢後,必須釋放系統資源,調用close方法,千萬記得。
  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操作次數,從而提高了讀寫的效率,建議開發中使用。

6. 常用操作:文件複製

複製圖片文件,代碼使用演示:

public class Copy {
    public static void main(String[] args) throws IOException {
        // 1.創建流對象
        // 1.1 指定數據源
        FileInputStream fis = new FileInputStream("D:\\test.jpg");
        // 1.2 指定目的地
        FileOutputStream fos = new FileOutputStream("test_copy.jpg");

        // 2.讀寫數據
        // 2.1 定義數組
        byte[] b = new byte[1024];
        // 2.2 定義長度
        int len;
        // 2.3 循環讀取
        while ((len = fis.read(b))!=-1) {
            // 2.4 寫出數據
            fos.write(b, 0 , len);
        }

        // 3.關閉資源
        fos.close();
        fis.close();
    }
}

Tips:

流的關閉原則:先開後關,後開先關。

6. 優化——文件複製

public static void main(String[] args) {
		/*
		try括號內的資源會在try語句結束後自動釋放,前提是這些
		可關閉的資源必須實現 java.lang.AutoCloseable 接口
		*/
        try(FileInputStream fis = new FileInputStream("D:\\test.jpg");
            FileOutputStream fos = new FileOutputStream("D:\\copy.jpg");){
            byte[] bytes = new byte[fis.available()];//存儲一次性讀取的字節流
            int len = 0;
            while((len = fis.read(bytes)) != -1){
                fos.write(bytes);
            }
        }catch (IOException e){
            e.printStackTrace();
        }
    }
    ```
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章