如果我们声明读取和写入资源,为什么抛出异常?

时间:2015-12-09 07:02:57

标签: java serialization

我正在尝试使用序列化并编写以下类:

public static void main(String[] args) throws ClassNotFoundException{
    File file = new File("D:/serializable.txt");
    try(FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream ous = new ObjectOutputStream(fos);
          FileInputStream fis = new FileInputStream(file);
          ObjectInputStream ois = new ObjectInputStream(fis)){
//      SerialTest st = new SerialTest();
//      ous.writeObject(st);
        SerialTest st = (SerialTest) ois.readObject();
        System.out.println(st);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

序列化类:

public static class SerialTest implements Serializable{

    private int count;

    private Object object;

    public int count(){
        return count;
    }

    public Object object(){
        return object;
    }

    private void readObject(ObjectOutputStream ous) throws IOException{
        ous.writeObject(object);
        ous.writeInt(count);
    }

    private void writeObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
        ois.readInt();
        ois.readObject();
    }
}

在序列化对象之后,如同在代码中一样,我试图按照此处的指定进行预期。我得到了

java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2598)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1318)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)

但是,包含序列化对象的文件的内容是chaged。

但是当我删除资源声明

FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream ous = new ObjectOutputStream(fos);
从try-with-resources clasuse

它完全正常。为什么?为什么资源声明会影响反序列化?

2 个答案:

答案 0 :(得分:2)

没有写入调用,您当前正在创建文件,因为这是您调用的FileOutputStream构造函数的内容确实。如果文件已存在,则将其截断为0字节长。因此,当您尝试从中读取对象时,无需阅读。

即使写作部分未被注释,仍然存在缓冲问题的可能性,其中数据尚未实际写入文件。

我强烈建议您编写文件并关闭输出流,然后单独打开它以进行输入。同时打开同一个文件进行读写可能会让我感到困惑。

所以代码看起来像这样:

// Exception handling omitted as this is just test code
public static void main(String[] args) throws Exception {
    File file = new File("D:/serializable.txt");
    try (FileOutputStream fos = new FileOutputStream(file);
         ObjectOutputStream ous = new ObjectOutputStream(fos)) {
        SerialTest st = new SerialTest();
        ous.writeObject(st);
    }
    try (FileInputStream fis = new FileInputStream(file);
         ObjectInputStream ois = new ObjectInputStream(fis)) { 
        SerialTest st = (SerialTest) ois.readObject();
        System.out.println(st);
    }
}

答案 1 :(得分:1)

撇开您显然将readObject()writeObject()的内容放回到前面的事实:

private void readObject(ObjectOutputStream ous) throws IOException{
    ous.writeObject(object);
    ous.writeInt(count);
}

这里首先是对象然后写整数。

private void writeObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{
    ois.readInt();
    ois.readObject();
}

这里首先读取整数然后是对象。

不会工作。

但是......你不需要这些方法。删除它们。或者,如果要序列化父类的数据,请将它们分别修改为(a)分别调用defaultReadObject()defaultWriteObject(),并删除已存在的内容,默认情况下已经发生,或者至少当您按照与编写它们相同的顺序读取对象和整数时,将它们存储到相应的实例成员中。

NB序列化数据不是文本,不应存储在名为.txt的文件中。