新しい ObjectInputStream で java.io.EOFException が発生するのはなぜですか

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;
        }
    }

おすすめ

転載: blog.csdn.net/m0_50370837/article/details/130935554