java位流(下)

14.2.4 DataInputStream和DataOutputStream

java.io.DataInputStream 和java.io.DataOutputStream可提供一些对Java基本数据类型写入的方法,像读写int、double和boolean等的方法。由于Java的数据类型大小是规定好的,在写入或读出这些基本数据类型时,就不用担心不同平台间数据大小不同的问题。

这里还是以文件存取来进行说明。有时只是要存储一个对象的成员数据,而不是整个对象的信息,成员数据的类型假设都是Java的基本数据类型,这样的需求不必要使用到与Object输入、输出相关的流对象,可以使用DataInputStream、DataOutputStream来写入或读出数据。

下面使用范例来介绍如何使用DataInputStream与DataOutputStream。先设计一个Member类。

ü 范例14.7  Member.java

package onlyfun.caterpillar;

public class Member {

    private String name;

    private int age;

    public Member() {

    }

    public Member(String name, int age) {

        this.name = name;

        this.age = age;

    }

    public void setName(String name) {

        this.name = name;

    }

    public void setAge(int age) {

        this.age = age;

    }

    public String getName() {

        return name;

    }

    public int getAge() {

        return age;

    }

}

打算将Member类实例的成员数据写入文件中,并打算在读入文件数据后,将这些数据还原为Member对象。范例14.8简单示范了如何实现这个需求。

ü 范例14.8  DataStreamDemo.java

package onlyfun.caterpillar;

import java.io.*;

public class DataStreamDemo {

    public static void main(String[] args) {

        Member[] members = {new Member("Justin", 90),

                              new Member("momor", 95),

                              new Member("Bush", 88)};

        try {

            DataOutputStream dataOutputStream =

                new DataOutputStream(

                         new FileOutputStream(args[0]));

          

            for(Member member : members) {

               // 写入UTF字符串

               dataOutputStream.writeUTF(member.getName());

               // 写入int数据

               dataOutputStream.writeInt(member.getAge());

            }

            // 读出所有数据至目的地

            dataOutputStream.flush();

            // 关闭流

            dataOutputStream.close();

          

            DataInputStream dataInputStream =

                new DataInputStream(

                         new FileInputStream(args[0]));

            // 读出数据并还原为对象

            for(int i = 0; i < members.length; i++) {

                // 读出UTF字符串

                String name = dataInputStream.readUTF();

                // 读出int数据

                int score = dataInputStream.readInt();

                members[i] = new Member(name, score);

            }

            // 关闭流

            dataInputStream.close();

            // 显示还原后的数据

            for(Member member : members) {

               System.out.printf("%s/t%d%n",

                       member.getName(), member.getAge());

            }

        }

        catch(IOException e) {

            e.printStackTrace();

        }

    }

}

在从文件中读出数据时,不用费心地自行判断读入字符串时或读入int类型时何时该停止,使用对应的readUTF()或readInt()方法就可以正确地读入完整类型数据。同样地, DataInputStream、DataOutputStream并没有改变InputStream或OutputStream的行为,读入或写出时的动作还是InputStream、OutputStream负责。DataInputStream、DataOutputStream只是在实现对应的方法时,动态地为它们加上类型判断功能,在这里虽然是以文件存取流为例,实际上可以在其他流对象上也使用DataInputStream、 DataOutputStream功能。

14.2.5 ObjectInputStream和ObjectOutputStream

在Java程序执行的过程中,很多数据都是以对象的方式存在于内存中。有时会希望直接将内存中整个对象存储至文件,而不是只存储对象中的某些基本类型成员信息,而在下一次程序运行时,希望可以从文件中读出数据并还原为对象。这时可以使用java.io.ObjectInputStream和java.io.ObjectOutputStream来进行这项工作。

如果要直接存储对象,定义该对象的类必须实现java.io.Serializable接口,不过Serializable接口中并没有规范任何必须实现的方法,所以这里所谓实现的意义,其实像是对对象贴上一个标志,代表该对象是可序列化的(Serializable)。

为了说明如何直接存储对象,先来实现一个User类。

ü范例14.9  User.java

package onlyfun.caterpillar;

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 1L;

  

    private String name;

    private int number;

    public User() {

    }

    public User(String name, int number) {

        this.name = name;

        this.number = number;

    }

    public void setName(String name) {

        this.name = name;

    }

  

    public void setNumber(int number) {

        this.number = number;

    }

    public String getName() {

        return name;

    }

    public int getNumber() {

        return number;

    }

}

注意到serialVersionUID,它代表了可序列化对象的版本。如果没有提供这个版本信息,则实现Serializable接口的类会自动依类名称、实现的接口、成员等来产生。如果是自动产生的,则下次更改User类,自动产生的serialVersionUID也会跟着变更,从文件读回对象时若两个对象的serialVersionUID不相同,就会丢出java.io.InvalidClassException。如果想要维持版本信息的一致,则要明确声明 serialVersionUID。

ObjectInputStream和 ObjectOutputStream为InputStream、OutputStream的实例加上了可以让用户写入对象与读出对象的功能。在写入对象时,要使用writeObject()方法,读出对象时则使用readObject()方法,被读出的对象都是以Object的类型返回。所以必须将之转换为对象原来的类型,才能正确地实现被读回的对象。范例14.10示范了如何存储User对象至文件中,然后再将它读回并还原为User实例。

ü 范例14.10  ObjectStreamDemo.java

package onlyfun.caterpillar;

import java.io.*;

import java.util.*;

public class ObjectStreamDemo {

    public static void main(String[] args) {

        User[] users = {new User("cater", 101),

                        new User("justin", 102)};

        // 写入新文件

        writeObjectsToFile(users, args[0]);

        try {

            // 读取文件数据

            users = readObjectsFromFile(args[0]);

            // 显示读回的对象

            for(User user : users) {

                System.out.printf("%s/t%d%n", user.getName(), user.getNumber());

            }

            System.out.println();

          

            users = new User[2];

            users[0] = new User("momor", 103);

            users[1] = new User("becky", 104);

          

            // 附加新对象至文件

            appendObjectsToFile(users, args[0]);

          

            // 读取文件数据

            users = readObjectsFromFile(args[0]);

            // 显示读回的对象

            for(User user : users) {

                System.out.printf("%s/t%d%n", user.getName(), user.getNumber());

            }

        }

        catch(ArrayIndexOutOfBoundsException e) {

            System.out.println("没有指定文件名");

        }

        catch(FileNotFoundException e) {

            e.printStackTrace();

        }

    }

    // 将指定的对象写入至指定的文件

    public static void writeObjectsToFile(

                         Object[] objs, String filename) {

        File file = new File(filename);

        try {

            ObjectOutputStream bjOutputStream =

                new ObjectOutputStream(

                      new FileOutputStream(file));

            for(Object obj : objs) {

                // 将对象写入文件

                objOutputStream.writeObject(obj);

            }

            // 关闭流

            objOutputStream.close();

        }

        catch(IOException e) {

            e.printStackTrace();

        }

    }

  

    // 将指定文件中的对象数据读回

    public static User[] readObjectsFromFile(

                             String filename)

                               throws FileNotFoundException {

        File file = new File(filename);

        // 如果文件不存在就丢出异常

        if(!file.exists())

            throw new FileNotFoundException();

        // 使用List先存储读回的对象

        List<User> list = new ArrayList<User>();

      

        try {

            FileInputStream fileInputStream =

                new FileInputStream(file);

            ObjectInputStream bjInputStream =

                new ObjectInputStream(fileInputStream);

          

            while(fileInputStream.available() > 0) {

                list.add((User) objInputStream.readObject());

            }

            objInputStream.close();

        }

        catch(ClassNotFoundException e) {

            e.printStackTrace();

        }

        catch(IOException e) {

            e.printStackTrace();

        }

        User[] users = new User[list.size()];

        return list.toArray(users);

    }

    // 将对象附加至指定的文件之后

    public static void appendObjectsToFile(

                           Object[] objs, String filename)

                               throws FileNotFoundException {

 

        File file = new File(filename);

        // 如果文件不存在则丢出异常

        if(!file.exists())

             throw new FileNotFoundException();

        try {

            // 附加模式

            ObjectOutputStream bjOutputStream =

               new ObjectOutputStream(

                  new FileOutputStream(file, true)) {

                    // 如果要附加对象至文件后

                    // 必须重新定义这个方法

                    protected void writeStreamHeader()

                                     throws IOException {}

               };

            for(Object obj : objs) {

                // 将对象写入文件

                objOutputStream.writeObject(obj);
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值