为什么我的序列化文件是 0 字节?为什么在读取它们时会抛出 EOF 错误?

Why are my serialized files 0 bytes? And why is it throwing an EOF error when reading them?

我正在做一个游戏项目,我正在创建一个保存功能。我正在使用序列化文件,以便直接保存对象并在以后检索它们。我只需要保存一个 ArrayList<Direction>,其中 Direction 是一个包含 UPDOWNLEFTRIGHT、[=19 的自定义枚举=] 和 RESTART 用于特殊情况。

在我的代码中,我创建了一个 ArrayList<Direction> 包含用户从游戏开始以来所做的每一个动作,并制作了一个保存按钮,将 ArrayList 存储在一个文件中。在文件中写入对象似乎没问题,没有抛出错误或其他任何错误。使用从文件中检索对象的加载按钮时,出现 EOF 错误(错误写在代码下方)。

我注意到我的文件是 0 字节,这让我想知道数据是否真的写入了文件,这可以解释 EOF 错误。我试过更改文件扩展名,在关闭它之前刷新 ObjectOutputStream,更改文件名,但是其中的 none 似乎可以解决问题。显然,我需要了解为什么我的文件是 0 字节(因此阻止我检索任何数据)以及为什么我在读取文件时遇到 EOF 错误。

这里是使用的代码:

public class LevelSaver {
    public LevelSaver() {
    }

    public void saveLevel(ArrayList<Direction> movesHistory, byte level) throws IOException {
        String fileName = "level" + (level < 10 ? "0" + level : level);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy @ HH-mm-ss");
        String currentTime = LocalDateTime.now().format(formatter);
        fileName += " " + currentTime;
        fileName += ".moves";

        File saveFile = new File("src\main\resources\level\saves\" + fileName);

        FileOutputStream fileOutputStream = null;
        ObjectOutputStream objectOutputStream = null;

        try {
            fileOutputStream = new FileOutputStream("src\main\resources\level\saves" + fileName);
            objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(movesHistory);
            objectOutputStream.flush();
        } catch (IOException exception) {
            exception.printStackTrace();
        }

        saveFile.createNewFile();
    }

    public ArrayList<Direction> getHistory(String fileName) {
        FileInputStream fileInputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            fileInputStream = new FileInputStream("src\main\resources\level\saves\" + fileName);
            objectInputStream = new ObjectInputStream(fileInputStream);
            return (ArrayList<Direction>) objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (objectInputStream != null) {
                try {
                    objectInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return new ArrayList<>();
    }
}

saveLevel() 创建一个 .mov 文件,其中包含 ArrayListgetHistory() returns 一个 ArrayList 存储在一个文件中。至少他们应该。

这是使用分别保存和加载移动历史记录的 F 和 G 键时发生的情况。

case F:
    try {
        levelSaver.saveLevel(movesHistory, currentLevel);
    } catch (IOException e) {
        e.printStackTrace();
    }
    direction = Direction.NULL;
    break;
case G:
    // I'm directly specifying the file and it is intended, the file name is correct
    ArrayList<Direction> res = levelSaver.getHistory("level06 09-04-2021 @ 22-08-57.mov");
    direction = Direction.NULL;
    for (Direction dir : res) {
        System.out.print("applied : " + dir);
        // apply moves applies the given move and changes the displayed map on the screen
        applyMove(dir);
    }
    break;

这是我在使用加载功能时遇到的错误。创建ObjectInputStream时出现错误。

java.io.EOFException
        at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2932)
        at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3427)
        at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:962)
        at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:405)
        at model.LevelSaver.getHistory(LevelSaver.java:41)
        at view.PlayingMenu.handle(PlayingMenu.java:150)
        at view.PlayingMenu.handle(PlayingMenu.java:87)
        at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
        at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:234)
        at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
        at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
        at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
        at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
        at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
        at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
        at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
        at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
        at javafx.graphics/javafx.scene.Scene$KeyHandler.process(Scene.java:4064)
        at javafx.graphics/javafx.scene.Scene.processKeyEvent(Scene.java:2123)
        at javafx.graphics/javafx.scene.Scene$ScenePeerListener.keyEvent(Scene.java:2591)
        at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:217)
        at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$KeyEventNotification.run(GlassViewEventHandler.java:149)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
        at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleKeyEvent(GlassViewEventHandler.java:248)
        at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:412)
        at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleKeyEvent(GlassViewEventHandler.java:247)
        at javafx.graphics/com.sun.glass.ui.View.handleKeyEvent(View.java:547)
        at javafx.graphics/com.sun.glass.ui.View.notifyKey(View.java:971)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
        at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop(WinApplication.java:174)
        at java.base/java.lang.Thread.run(Thread.java:832)

您没有关闭任何一个流。

使用 try-with-resources:

    try (FileOutputStream fileOutputStream = new FileOutputStream("src\main\resources\level\saves" + fileName);
         ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
        objectOutputStream.writeObject(movesHistory);
    } catch (IOException exception) {
        exception.printStackTrace();
    }