系统学习 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 的教程了。

相关文章
相关标签/搜索