Java 基礎(四)| IO 流之使用文件流的正確姿式

爲跳槽面試作準備,今天開始進入 Java 基礎的複習。但願基礎很差的同窗看完這篇文章,能掌握泛型,而基礎好的同窗權當複習,但願看完這篇文章可以起一點你的青澀記憶。前端

1、什麼是 IO 流?

想象一個場景:咱們在電腦上編輯文件,能夠保存到硬盤上,也能夠拷貝到 U 盤中。那這個看似簡單的過程,背後實際上是數據的傳輸。java

數據的傳輸,也就是數據的流動。既然是流動也就會有方向,有入方向和出方向。舉個上傳文件的栗子,如今有三個對象,文件、應用程序、上傳的目標地址(服務器)。簡化的上傳文件有兩步:python

  • 應用程序讀文件(此爲入方向,文件讀入到應用程序)
  • 應用程序寫文件(此爲出方向,讀完以後寫到目標地址)

注意這個入和出是相對的,它相對於應用程序而言。若是相對於服務器而言,這個上傳文件操做就是入方向,從應用程序讀入。Java中I/O操做主要是指使用java.io包下的內容,進行輸入、輸出操做。輸入也叫作讀取數據,輸出也叫作做寫出數據。linux

2、IO 流的分類

我不認同網絡上不少 IO 流的圖,他們只是簡單的把 io 流分紅字節流和字符流。這樣的分類也不是說很差,只是太臃腫、難記。c++

先上一張我本身總結的 IO 留的思惟導圖,我先把它分紅了節點流處理流節點流是直接接觸數據源的,而處理流是出於各類目的在節點流的基礎上再套一層的 IO 流。再按照操做類型,分紅 8 個小類,而後纔是字節、字符分類,最後纔是輸入、輸出的分類。具體能夠看如下思惟導圖(可能不清晰,有須要的在後臺回覆IO流獲取原思惟導圖)git

根據數據的流向分爲:輸入流輸出流github

  • 輸入流 :把數據從其餘設備上讀取到內存中的流。
  • 輸出流 :把數據從內存 中寫出到其餘設備上的流。

根據數據的類型分爲:字節流字符流面試

  • 字節流 :以字節爲單位,讀寫數據的流。
  • 字符流 :以字符爲單位,讀寫數據的流。

Java IO 流

IO 流要說明白鬚要好幾篇才行,今天咱們先複習文件流。算法

2.1 一切皆字節

全部的文件(包括圖片、音樂、視頻),都是字節。因此字節流能夠傳輸任意文件數據。在操做流的時時,不管使用什麼樣的流對象,底層傳輸的始終爲二進制數據。小程序

2.2 什麼叫文件流?

文件流也就是直接操做文件的流,文件流又分爲字節流 (FileInputStreamFileOutputStream)和字符流(FileReaderFileWriter)。其中字節流可用於操做一切文件,而字符流只能用於操做文本文件。

3、使用文件字節流

字節輸出流

字節輸入流

3.1 FileOutputStream

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

構造方法:可用文件路徑構造,也可建立 File 對象以後構造。

寫出數據示例:

/** * Project Name:review_java <br/> * Package Name:com.nasus.io.filestream <br/> * Date:2020/1/5 19:24 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class FOSWriterStream {

    public static void main(String[] args) throws IOException {
        // 使用文件名稱建立流對象,構造函數中的 true 表示在原有數據末尾追加續寫
        FileOutputStream fos = new FileOutputStream("fos.txt", true);

        // 一、逐個字節寫出
        fos.write(97); // 97 的 ascll 碼是 a
        fos.write(98); // 98 的 ascll 碼是 b
        fos.write(99); // 99 的 ascll 碼是 c

        // 二、寫出一個換行, 換行符號轉成數組寫出
        fos.write("\r\n".getBytes());

        // 字符串轉換爲字節數組
        byte[] b = "一個優秀的廢人".getBytes();
        // 三、寫出字節數組數據
        fos.write(b);

        // 四、寫出指定長度字節數組數據(不可超過 b 的長度,不然數組越界)
        fos.write(b, 0, b.length);

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

}
複製代碼

3.2 FileInputStream

java.io.FileInputStream類繼承於 InputStream 是文件輸入流,用於將數據從文件讀出。

構造方法:可用文件路徑構造,也可建立 File 對象以後構造。

讀取數據示例:

/** * Project Name:review_java <br/> * Package Name:com.nasus.io.filestream <br/> * Date:2020/1/5 19:31 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class FISReadStream {

    public static void main(String[] args) throws IOException {
        // 一、逐個讀取字節
        int b;
        FileInputStream fis1 = new FileInputStream("fis.txt");
        // 循環讀取
        while ((b = fis1.read())!=-1) {
            System.out.println((char)b);
        }
        // 關閉資源
        fis1.close();

        System.out.println("----華麗麗的分割線----");

        // 二、定義字節數組讀取
        int length;
        FileInputStream fis2 = new FileInputStream("fis.txt");
        // 定義字節數組,做爲裝字節數據的容器
        byte[] bytes = new byte[1024];
        // 循環讀取
        while ((length = fis2.read(bytes))!=-1) {
            // 每次讀取後,把數組變成字符串打印
            System.out.println(new String(bytes, 0, length));
        }
        // 關閉資源
        fis2.close();
    }

}
複製代碼

複製文件示例:

/** * Project Name:review_java <br/> * Package Name:com.nasus.io.filestream <br/> * Date:2020/1/5 19:43 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class FileCopyStream {

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

        // 指定數據源
        FileInputStream fis = new FileInputStream("Java IO 流.png");
        // 指定目的地
        FileOutputStream fos = new FileOutputStream("流.png");

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

        // 關閉資源,後開先關,後開先關
        fos.close();
        fis.close();
    }

}
複製代碼

3.3 爲何字節流處理中文字符時會出現亂碼?

首先明確一點:一個英文字母佔一個字節,一個漢字佔兩個字節,因此當字節流讀取字符流就會出現亂碼或者顯示不全。因此用字節流操做含有中文字符的文件時,要轉換成字符流並指定編碼格式才能防止亂碼。(這點,後面轉換流會複習到

4、使用文件字符流

當使用字節流讀取文本文件時,可能會有一個小問題。就是遇到中文字符時,可能不會顯示完整的字符,那是由於一箇中文字符可能佔用多個字節存儲。因此 Java 提供一些字符流類,以字符爲單位讀寫數據,專門用於處理文本文件。

字符輸入流

字符輸出流,寫文件

4.1 FileReader

java.io.FileReader類繼承於 Reader 類,是讀取字符文件的便利類。構造時使用系統默認的字符編碼和默認字節緩衝區。

構造方法:可用文件路徑構造,也可建立 File 對象以後構造。

  • 字符編碼:字節與字符的對應規則。Windows 系統的中文編碼默認是 GBK 編碼表
  • 字節緩衝區:一個字節數組,用來臨時存儲字節數據。

PS:有時候出現亂碼,多考慮下是否是編碼的緣由:字節與字符的規則對不上。

讀取數據示例:

/** * Project Name:review_java <br/> * Package Name:com.nasus.io.filereadwrite <br/> * Date:2020/1/5 20:19 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class FileRead {

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

        // 一、逐個字符讀取
        int b = 0;
        FileReader fileReader1 = new FileReader("read.txt");
        // 循環讀取
        while ((b = fileReader1.read())!=-1) {
            // 自動提高類型提高爲 int 類型,因此用 char 強轉
            System.out.println((char)b);
        }
        // 關閉流
        fileReader1.close();

        System.out.println("----華麗麗的分割線----");

        // 二、利用字符數組,每次讀取兩個字符
        int length = 0;
        FileReader fileReader2 = new FileReader("read.txt");
        char[] charArray = new char[2];
        // 讀取數據
        while ((length = fileReader2.read(charArray)) != -1) {
            System.out.println(new String(charArray, 0, length));
        }
        // 關閉流
        fileReader2.close();
    }

}
複製代碼

4.2 FileWriter

java.io.FileWriter類是寫出字符到文件的便利類。構造時使用系統默認的字符編碼和默認字節緩衝區。

構造方法:可用文件路徑構造,也可建立 File 對象以後構造。

寫出數據示例:

public static void main(String[] args) throws IOException {
        // 使用文件名稱建立流對象,true 表示在原有數據末尾追加續寫
        FileWriter fileWriter = new FileWriter("fw.txt", true);

        // 一、逐個寫出字符
        fileWriter.write(97);
        fileWriter.write('C');
        fileWriter.write('Z');
        fileWriter.write('Y');
        // 中文編碼表中30000對應一個漢字。
        fileWriter.write(30000);


        // 二、寫出字符串
        fileWriter.write("是一個");

        // 三、寫出 Windows 換行
        fileWriter.write("\r\n");

        // 四、寫出字符串數組
        // 字符串轉換爲字節數組
        char[] chars = "優秀的廢人".toCharArray();
        fileWriter.write(chars, 0, chars.length);

        // 關閉資源,close方法調用以前,數據只是保存到了緩衝區,並未寫出到文件中。
        fileWriter.close();
    }
複製代碼

刷新與關閉:

由於內置緩衝區的緣由,若是不關閉輸出流,沒法寫出字符到文件中。可是關閉的流對象,是沒法繼續寫出數據的。若是咱們既想寫出數據,又想繼續使用流,就須要flush 方法了。

  • flush :刷新緩衝區,流對象能夠繼續使用。
  • close:先刷新緩衝區,而後通知系統釋放資源。流對象不能夠再被使用了。
/** * Project Name:review_java <br/> * Package Name:com.nasus.io.filereadwrite <br/> * Date:2020/1/5 22:25 <br/> * * @author <a href="turodog@foxmail.com">chenzy</a><br/> */
public class FileFlushClose {

    public static void main(String[] args) throws IOException {
        // 使用文件名稱建立流對象
        FileWriter fw = new FileWriter("fw.txt");
        // 一、經過 flush 寫出數據
        // 寫出第 1 個字符
        fw.write('刷');
        fw.flush();

        // 繼續寫出第 2 個字符,寫出成功
        fw.write('新');
        fw.flush();

        // 二、經過 close 寫出數據,流關閉後不可用
        // 寫出第 1 個字符
        fw.write('關');
        fw.close();

        // 繼續寫出第 2 個字符,【報錯】java.io.IOException: Stream closed
        fw.write('閉');
        fw.close();
    }
}
複製代碼

5、源碼地址

若是看到這裏,喜歡這篇文章的話,幫忙 " 轉發 "或者點個" 在看 ",行嗎?祝大家 2020 暴富。微信搜索「一個優秀的廢人」,歡迎關注。

回覆「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大數據、人工智能、小程序以及英語教程。

回覆「電子書」送你 50+ 本 java 電子書。

最全教程
相關文章
相關標籤/搜索