1. コード例
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\\宿題06\\ のパスの下にstudent.txt ファイルを作成し、プログラムを実行します。
EOFExceptionが発生することが分かりました。どうしてこれなの?
次に、理由を分析します
デバッグの形式を使用して、理由を段階的に分析します。
例外情報には、 ois = new ObjectInputStream(new FileInputStream("src\\com\\softeem\\wolf\\宿題06\\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;
}
}
return 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 ファイルが空であるため、ファイル ヘッダー ストリームを取得できず、カウントが -1 になり、EOFException 例外が発生します。 。
3、解決策
解決策も非常に簡単です。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\\宿題06\\student.txt")) となるため、
writeStreamHeader() メソッドはファイル ヘッダーを書き込むため、readStreamHeader() メソッドの実行時に ObjectInputStream() コンストラクターがファイル ヘッダーを検出できなくなる可能性があります。
以下は、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;
}
}