Java中的IO流 - 入門篇

語言: CN / TW / HK

前言

大家好啊,我是湯圓,今天給大家帶來的是《Java中的IO流-入門篇》,希望對大家有幫助,謝謝

由於Java的IO類有很多,這就導致我剛開始學的時候,感覺很亂,每次用到都是上網搜,結果每次用完就忘;

後來沉下心去看書學習,才明白都是有規律的;

這裡先做個簡單的介紹,作為入門級教程,後面還有很多要學習的,有空再整理吧。

簡介

檔案IO流,主要有兩種方式

  1. 位元組流:基於普通的Java物件,僅適用於Java程式之間的讀寫
  2. 字元流:基於普通的文字字串,不僅適用於Java程式之間的讀寫,也適用於Java程式和其他語言程式之間的讀寫

本例中用到的相關類如下:

IO流

所有的讀寫操作都是針對記憶體而言的,因為程式就是執行記憶體

讀操作就是從磁碟檔案或網路流讀到記憶體,對於記憶體而言就是Input

寫操作就是從記憶體寫到磁碟檔案或網路流,對於記憶體而言就是Output

下面分別介紹這兩種方式

位元組流:基於普通的Java物件

位元組流的讀和寫都是基於Java程式而言,比如在一個機器上的Java程式寫入一個物件到檔案,然後傳輸到另一個機器上的Java程式去讀取檔案中的物件

寫入Java物件時,會先將Java物件序列化(物件轉為位元組),然後寫入

讀取Java物件時,會先將Java物件反序列化(位元組轉為物件),然後讀取

寫物件

將物件寫入到檔案中,需要先把物件序列化,然後再把序列化後的位元組寫入到檔案中;

序列化就是將物件的屬性資訊轉為一系列位元組(不包括transient 型別的屬性,下面會介紹)

大概流程如下所示:

序列化

讀物件

將物件從檔案中讀出來,需要先反序列化,然後再轉為對應的Java物件,並恢復物件屬性值

反序列化就是將一系列位元組轉為真實的物件例項(不包括transient型別的屬性)

大概流程如下所示:

反序列化

transient

該修飾符 字面意思是瞬時的,短暫的

用在物件的屬性上,就表示這個屬性是暫時有效的,等序列化的時候會失效

在反序列化的時候,這個屬性就會為null(如果屬性是物件引用)或基礎型別的預設值(如果屬性是基礎型別)

比如密碼等比較隱私的屬性,我們就可以設定為transient,這樣就不會在傳輸過程中被被人攔截,從而破解出密碼

程式碼

public class ObjectIoDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        InnerObject object1 = new InnerObject(10);
        String filename = "object.bin";
        writeObjectFun(filename, object1);
        InnerObject objectReturn = (InnerObject) readObjectFun(filename);
        System.out.println(objectReturn);

    }

    // 寫物件 到指定檔案
    public static void writeObjectFun(String filename, Object o) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(filename);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(o);
        // 關閉流,fileOutputStream會一併關閉
        objectOutputStream.close();
    }

    // 讀物件 從指定檔案
    public static Object readObjectFun(String filename) throws IOException, ClassNotFoundException {
        FileInputStream fileInputStream = new FileInputStream(filename);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        Object o = objectInputStream.readObject();
        // 關閉流,fileInputStream會一併關閉
        objectInputStream.close();
        return o;
    }
}
class InnerObject implements Serializable{

    @Override
    public String toString() {
        return "InnerObject{" +
                "num=" + num +
                '}';
    }

    public InnerObject(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    private int num;
}

如果要寫入的Java物件沒有序列化,則會報錯如下

Exception in thread "main" java.io.NotSerializableException: com.jalon.basic.io.InnerObject
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at com.jalon.basic.io.ObjectIoDemo.writeObjectFun(ObjectIoDemo.java:28)
	at com.jalon.basic.io.ObjectIoDemo.main(ObjectIoDemo.java:19)

字元流:基於普通文字字串

字元流寫入到檔案中的資料,是作為通用文字資料來處理的,這樣Java程式和其他程式都可以去讀寫這個檔案

寫文字

大致流程如下:

寫文字

讀文字

大致流程如下:

讀文字

BufferedReader和BufferedWriter的作用

為什麼要用緩衝區呢?直接用FileReader和FileWriter不也可以嗎?

如果直接用FileWriterFileReader是可以執行,只不過效率會比較低,因為每一次的讀寫都是針對磁碟操作的;

BufferedWriterBufferedReader這兩個緩衝區可以減少磁碟的讀寫次數;

BufferedReader:程式可以從磁碟一次性讀很多資料到緩衝區,再從緩衝區一次次讀,等緩衝區為空時再去磁碟讀;

BufferedWriter:程式可以寫多次到緩衝區,等快取區滿了再一次性寫入到磁碟中

程式碼

public class TextIoDemo {
    public static void main(String[] args) throws IOException {
        String filename = "string.txt";
        writeString(filename, "hello world");
        String res = readString(filename);
        System.out.println(res);
    }
	// 寫字串到指定檔案
    public static void writeString(String filename, String content) throws IOException {
        FileWriter fileWriter = new FileWriter(filename);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        bufferedWriter.write(content);

        bufferedWriter.close();
    }
	// 從指定檔案讀取字串
    public static String readString(String filename) throws IOException {
        FileReader fileReader = new FileReader(filename);
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        String line = "";
        StringBuilder stringBuilder = new StringBuilder();
        while ((line=bufferedReader.readLine())!=null){
            stringBuilder.append(line);
        }
        bufferedReader.close();
        return stringBuilder.toString();
    }
}

總結

IO流分為位元組流字元流

如果讀寫兩邊都是Java程式,則推薦用位元組流,序列化和反序列化很方便

如果一邊是Java程式,另一邊是其他語言的程式,則推薦用字元流,讀寫的內容都是文字格式,方便解析

上面只是列出了個別讀寫類,Java中讀寫類還有很多,大家感興趣的可以去java.io下檢視

IO包

參考

  1. 《Head First Java》(第二版)
  2. 《Java 核心技術卷一》(第十版)
  3. 《Java 程式設計思想》(第四版)

後記

最後,感謝大家的觀看,謝謝

分享到: