1

我们的应用程序中存在一个问题,可以简化为以下代码:

public static void main(String[] args) throws IOException, ClassNotFoundException {
        File tempFile = File.createTempFile("teststream", "");
        FileOutputStream fos = new FileOutputStream(tempFile);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeInt(1);
        oos.writeObject("foo");
        oos.writeInt(2);
        oos.flush();
        oos.close();
        FileInputStream fis = new FileInputStream(tempFile);
        ObjectInputStream ois = new ObjectInputStream(fis);
        int n1 = ois.readInt();
        Object o1 = ois.readObject();
        int n2 = ois.readInt();
    }

此代码有效,但如果您评论以下行:

Object o1 = ois.readObject();

以下行

int n2 = ois.readInt();

会抛出一个EOFException尽管我的文件中有数据,因为我在其中写了一个对象和一个整数。readInt的javadoc没有指出这种行为。我有点担心这一点EOFException,因为我们想在我们的代码中区分真正的文件异常和错误类型的内容

异常的堆栈跟踪是

Exception in thread "main" java.io.EOFException
    at java.io.DataInputStream.readInt(DataInputStream.java:392)
    at java.io.ObjectInputStream$BlockDataInputStream.readInt(ObjectInputStream.java:2793)
    at java.io.ObjectInputStream.readInt(ObjectInputStream.java:968)

这意味着以下代码DataInputStream会引发异常:

 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();

但是in.read()当输入流中有数据时不应该返回负数,所以我真的很感兴趣。

在我的代码中是否可以做一些事情来防止这种情况发生(知道我们可能会在某个时候调用readIndwhere writeObjectwas used)?

我正在使用这个版本的java:

java version "1.7.0_07"
OpenJDK Runtime Environment (IcedTea7 2.3.2) (ArchLinux build 7.u7_2.3.2-2-x86_64)
OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)
4

3 回答 3

5

底层流以块的形式写入,带有块头。当您尝试readInt写入对象时,会发现错误的块类型并in.read()返回 -1。

调用以下方法。

    /**
     * Attempts to read in the next block data header (if any).  If
     * canBlock is false and a full header cannot be read without possibly
     * blocking, returns HEADER_BLOCKED, else if the next element in the
     * stream is a block data header, returns the block data length
     * specified by the header, else returns -1.
     */
    private int readBlockHeader(boolean canBlock) throws IOException {
         // code deleted
                int tc = in.peek();
                switch (tc) {
                    case TC_BLOCKDATA:
         // code deleted
                    default:
                        if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
                            throw new StreamCorruptedException(
                                String.format("invalid type code: %02X",
                                tc));
                        }
                        return -1;
    }

StreamCorruptedException-1 意味着当 a在这里可能是一个更好的选择时,已经达到了终点。

于 2012-09-26T09:49:12.887 回答
1

如果您注释该行,Object o1 = ois.readObject();并且您执行程序,n2则不会读取int,而是从序列化对象中读取 4 个字符。是的,你可以得到一个负值,这取决于对象的序列化方式(例如,存储对象的字节序,如果我没记错的话,它存储在 Big-Endian 中)。

于 2012-09-26T09:12:36.133 回答
1

情况完全无效。如果您不阅读您所写的内容,则行为是未定义的。在这种情况下它可能不应该抛出一个EOFException错误,但是由于你不能指出一个说明当你做错事情时应该做什么的规范,你真的没有立足之地。

于 2012-09-27T00:50:19.773 回答