new一个ObjectInputStream为什么会出现java.io.EOFException

一、举例代码

package com.softeem.wolf.homework06;

import java.io.*;

/**
 * Created by 苍狼
 * Time on 2023-05-24
 */
public class App {
    public static void main(String[] args) throws IOException {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        ois = new ObjectInputStream(new FileInputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"));
        oos = new ObjectOutputStream(new FileOutputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"));
        
        Student student1 = new Student(1,"张三",'男');
        Student student2 = new Student(2, "李四",'女');

        try {
            oos.writeObject(student1);
            oos.writeObject(student2);
            oos.writeObject(null);
            oos.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        try {
            Object object;
            while((object=ois.readObject())!=null){
                System.out.println(object);
            }
            ois.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            ois.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
}

在src\\com\\softeem\\wolf\\homework06\\路径下新建一个student.txt文件,运行程序。

发现会出现EOFException异常。这是为什么呢?

二、分析原因

我们用debugs的形式一步一步分析原因。

异常信息显示ois = new ObjectInputStream(new FileInputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"));出现问题,

我们点进去看一ObjectInputStream的构造器

public ObjectInputStream(InputStream in) throws IOException {
        verifySubclass();
        bin = new BlockDataInputStream(in);
        handles = new HandleTable(10);
        vlist = new ValidationList();
        enableOverride = false;
        readStreamHeader();
        bin.setBlockDataMode(true);
    }

发现这里会调用一个readStreamHeader()方法,获取文件中数据流的头,然后我们在点进去看看这个readStreamHeader()方法。

protected void readStreamHeader()
        throws IOException, StreamCorruptedException
    {
        short s0 = bin.readShort();
        short s1 = bin.readShort();
        if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
            throw new StreamCorruptedException(
                String.format("invalid stream header: %04X%04X", s0, s1));
        }
    }

这个方法调用了bin.readShort(),看看readShort()方法的源码。

public short readShort() throws IOException {
            if (!blkmode) {
                pos = 0;
                in.readFully(buf, 0, 2);
            } else if (end - pos < 2) {
                return din.readShort();
            }
            short v = Bits.getShort(buf, pos);
            pos += 2;
            return v;
        }

发现它会调用in.readFully(buf, 0,2)这个方法,接着去这个方法的源码下看看。

void readFully(byte[] b, int off, int len) throws IOException {
            int n = 0;
            while (n < len) {
                int count = read(b, off + n, len - n);
                if (count < 0) {
                    throw new EOFException();
                }
                n += count;
            }
        }

接着在这个方法中调用read(b, off+n, len-n), 我们来看看这个源码。

public int read(byte[] b, int off, int len) throws IOException {
            if (len == 0) {
                return 0;
            } else if (peekb < 0) {
                return in.read(b, off, len);
            } else {
                b[off++] = (byte) peekb;
                len--;
                peekb = -1;
                int n = in.read(b, off, len);
                return (n >= 0) ? (n + 1) : 1;
            }
        }

它会运行到renturn in.read(b, off, len); 我们接着点进去看这个源码。

public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

这个方法最终返回的结果是-1;然后一直把结果往上传,传到readFully(byte[] b, int off, int len)方法进行判断,如果count<0,则抛出 EOFException异常。这就是new ObjectInputStream()对象的整个过程。

这个ObjectInputStream构造器中的readStreamHeader()方法就是获取文件头的流,但是由于我们这个student.txt文件是空的,所以获取不到文件头流,导致count为-1,从而出现EOFException异常。

三、解决办法

解决办法也很简单。只需要将new ObjectOutputStream()和new ObjectInputStream()顺序调换就行。

package com.softeem.wolf.homework06;

import java.io.*;

/**
 * Created by 苍狼
 * Time on 2023-05-24
 */
public class App {
    public static void main(String[] args) throws IOException {
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        oos = new ObjectOutputStream(new FileOutputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"));
        ois = new ObjectInputStream(new FileInputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"));
        Student student1 = new Student(1,"张三",'男');
        Student student2 = new Student(2, "李四",'女');

        try {
            oos.writeObject(student1);
            oos.writeObject(student2);
            oos.writeObject(null);
            oos.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
        try {
            Object object;
            while((object=ois.readObject())!=null){
                System.out.println(object);
            }
            ois.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            ois.close();
        } catch (IOException ioException) {
            ioException.printStackTrace();
        }
    }
}

运行结果

因为oos = new ObjectOutputStream(new FileOutputStream("src\\com\\softeem\\wolf\\homework06\\student.txt"))在运行的时候,构造器中

writeStreamHeader()方法会将文件头写进去,这就可以避免ObjectInputStream()构造器在运行readStreamHeader()方法时检测不到文件头。

下面是ObjectOutputStream中构造器的源码。

public ObjectOutputStream(OutputStream out) throws IOException {
        verifySubclass();
        bout = new BlockDataOutputStream(out);
        handles = new HandleTable(10, (float) 3.00);
        subs = new ReplaceTable(10, (float) 3.00);
        enableOverride = false;
        writeStreamHeader();
        bout.setBlockDataMode(true);
        if (extendedDebugInfo) {
            debugInfoStack = new DebugTraceInfoStack();
        } else {
            debugInfoStack = null;
        }
    }

猜你喜欢

转载自blog.csdn.net/m0_50370837/article/details/130935554