系統學習 Java IO (十二)----數據流和對象流

目錄:系統學習 Java IO---- 目錄,概覽html

DataInputStream/DataOutputStream

容許應用程序以與機器無關方式從底層輸入流中讀取基本 Java 數據類型。java

要想使用數據輸出流和輸入流,必須按指定的格式保存數據,才能夠將數據輸入流將數據讀取進來,因此一般使用 DataInputStream 來讀取 DataOutputStream 寫入的數據。瀏覽器

DataInputStream 類可以從 InputStream 中讀取 Java 基本類型(int,float,long等),而不單單是原始字節。 將InputStream包裝在 DataInputStream 中,就能夠從 DataInputStream 中讀取 Java 基本類型。 這就是爲何它被稱爲 DataInputStream - 由於它讀取數據(數字)而不單單是字節。工具

若是須要讀取的數據包含大於一個字節的Java 基本類型,則 DataInputStream 很是方便。DataInputStream 但願接受有序多字節類型數據。學習

同時使用 DataInputStream 和 DataOutputStream

如前所述,DataInputStream 類一般與 DataOutputStream 一塊兒使用,首先使用 DataOutputStream 寫入數據,而後使用 DataInputStream 再次讀取數據。 如下是示例Java代碼:優化

public class DataStream {
    public static void main(String[] args) throws IOException {
        String file = "D:\\test\\output.txt";
        DataOutputStream output = new DataOutputStream(new FileOutputStream(file));
        output.write(1); // 默認是 byte
        output.writeInt(123); // 指定寫入 int
        output.writeInt(321);
        output.writeLong(789);
        output.writeFloat(123.45f);
        output.close();

        // 必定要按照寫入的順序和類型讀取,不然會出錯;
        DataInputStream input = new DataInputStream(new FileInputStream(file));
        byte b = (byte) input.read();
        int i1 = input.readInt();
        int i2 = input.readInt();
        Long l = input.readLong();
        Float f = input.readFloat();
        input.close();

        System.out.println("i1 = " + i1);
        System.out.println("i2 = " + i2);
        System.out.println("b = " + b);
        System.out.println("l = " + l);
        System.out.println("f = " + f);
    }
}

注意:必定要按照寫入的順序和類型讀取,不然會出錯;
其實 DataInputStream 類的實現中,讀取方法中只有一個 read() 方法是真正幹活,其餘的 readXXX() 都是調用 read() 完成任務。看以下代碼:ui

public final byte readByte() throws IOException {
        int ch = in.read();
        if (ch < 0)
            throw new EOFException();
        return (byte)(ch);
    }

    public final char readChar() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        if ((ch1 | ch2) < 0)
            throw new EOFException();
        return (char)((ch1 << 8) + (ch2 << 0));
    }

    public final int readInt() throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

能夠看到,XXX 佔 多少個字節,就會在其內部調用多少次 read() 方法。code

ObjectInputStream/ObjectOutputStream

和 DataInputStream 包裝成 Java 基本類型相似,ObjectInputStream 類可以從 InputStream 中讀取Java對象,而不單單是原始字節。 固然,讀取的字節必須表示有效的序列化 Java 對象。 一般,使用 ObjectInputStream 來讀取 ObjectOutputStream 編寫(序列化)的對象。
下面是一個例子:htm

public class ObjectStream {
    public static void main(String[] args) throws Exception {
        // Serializable 是一個標識接口,實現類只要承諾能被序列化就好了
        class People implements Serializable {
            String name;
            int age;
        }
        File file = new File("D:\\test\\object.data");

        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file));
        People someOne = new People();
        someOne.name = "Json";
        someOne.age = 18;
        output.writeObject(someOne);
        output.close();

        ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));
        People people = (People) input.readObject();
        System.out.println("name = " + people.name + ", age = " + people.age);
        input.close();
    }
}
Close()

使用完數據流後記得關閉它。 關閉 DataInputStream 還將關閉 DataInputStream 正在讀取的 InputStream 實例。可使用 try-with-resources 方式自動關閉。ObjectInputStream 同理。對象

Serializable

若是一個類要進行序列化和反序列化,就必須實現 Serializable 標記接口,這樣就可使用 ObjectOutputStream 完成 Java 對象序列化(寫入),使用 ObjectInputStream 完成反序列化(讀取)。

Serializable 是一個標記接口意味着它不包含任何方法。 所以,實現 Serializable 的類沒必要實現任何特定方法,只是告訴 Java 該類對象支持序列化。

serialVersionUID

除了實現 Serializable 接口以外,用於序列化的類還應包含名爲 serialVersionUID 的 private static final long 變量。
Java 的對象序列化 API 使用 serialVersionUID 變量來肯定反序列化對象是不是使用相同版本的類進行序列化的,由於它如今正嘗試將其反序列化。

想象一下,Person 對象被序列化爲磁盤。 而後對 Person 類進行更改。 而後反序列化存儲的 Person 對象。 這樣,序列化的 Person 對象可能與 Person 類的新版本不對應。
要檢測此類問題,實現 Serializable 的類應包含 serialVersionUID 字段。 若是對類進行了重大更改,則還應更改其 serialVersionUID 值。
許多 Java IDE 包含生成 serialVersionUID 的工具,可使用工具生成的 UID 。

在今天的世界(2015年以後)中,許多 Java 項目使用與 Java 序列化機制不一樣的機制來序列化 Java 對象。 例如,Java 對象被序列化爲 JSON,BSON 或其餘更優化的二進制格式。 這具備如下優勢:對象也可由非 Java 應用程序讀取。 例如,在 Web 瀏覽器中運行的 JavaScript 能夠本地序列化和反序列化 JSON 中的對象。 順便說一下,這些其餘對象序列化機制一般不須要 Java 類實現 Serializabl e。 他們一般使用 Java 反射來檢查類,這裏是 Java IO 教程,具體要看看 Java Json 的教程了。

相關文章
相關標籤/搜索