一、举例代码
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;
}
}