java - 读取包含对象的文件时,ObjectInputStream 抛出 EOFException

标签 java serialization objectinputstream eofexception

我正在尝试从文件中读取Treemap。我知道文件中有一个 TreeMap 序列化,我的问题是 OIS 在该文件上抛出 EOFException

public class FileDBMapApi {

    private FileOutputStream OutPutter;
    private FileInputStream Inputter;
    private ObjectInputStream InputStream;
    private ObjectOutputStream OutputStream;
    private NavigableMap<Integer, Object> data;
    private File currentFile;
    private int autoIncrement;

    /**
     * @param dataFile is the file to use as a database
     */
    public FileDBMapApi(String dataFile) {
        String fullPath = "data/" + dataFile;
        currentFile = new File(fullPath);
    }

    // initialiserar databasen
    public void init() {
        // checkar om filen existerar och isåfall assignar inputter och outputter till filen
        System.out.println(currentFile.exists() && !currentFile.isDirectory());
        if (currentFile.exists() && !currentFile.isDirectory()) {
            try {
                OutPutter = new FileOutputStream(currentFile);
                OutPutter.flush();
                Inputter = new FileInputStream(currentFile);
                OutputStream = new ObjectOutputStream(OutPutter);
                OutputStream.flush();
                InputStream = new ObjectInputStream(Inputter);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // annars så skapar den filen och assignar det istället
            try {
                boolean temp1 = currentFile.getParentFile().mkdirs();
                boolean temp2 = currentFile.createNewFile();
                if (temp2) {
                    OutPutter = new FileOutputStream(currentFile);
                    Inputter = new FileInputStream(currentFile);
                    OutputStream = new ObjectOutputStream(OutPutter);
                    InputStream = new ObjectInputStream(Inputter);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // läser in hashmapen från filen
        this.convertData();
    }

    public void write() {
        try {
            PrintWriter n = new PrintWriter(currentFile);
            n.close();
            OutputStream.writeObject(data);
            OutputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public int add(Object o) {
        int id = autoIncrement;
        data.put(autoIncrement, o);
        autoIncrement++;
        return id;
    }

    public Object get(int i) {
        return data.get(i);
    }

    public void close() {
        try {
            OutPutter.close();
            Inputter.close();
            InputStream.close();
            OutputStream.flush();
            OutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // returnar data
    public NavigableMap<Integer, Object> getAll() {
        return data;
    }

    public long getFileSize() {
        return currentFile.length();
    }

    // tar data från en fil och sätter in det till en hashmap
    private void convertData() {
        try {
            if (InputStream.read() != -1) {
                data = (NavigableMap) InputStream.readObject();
            } else {
                data = new TreeMap<>();
                System.out.println(data);
            }
            if (!data.isEmpty()) autoIncrement = data.lastKey();
            else autoIncrement = 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void closeAndWrite() {
        write();
        close();
    }

}

正是 convertData(0) 方法引发了异常。我检查了相关文件,它确实包含一个序列化的 Treemap,它已使用 write() 方法和 close() 方法进行序列化。现在我的问题是我在存储或检索数据时在哪里做错了?

最佳答案

我会找到错误所在,但实际上您的代码毫无意义,需要彻底审查:

public class FileDBMapApi {

    private FileOutputStream OutPutter;
    private FileInputStream Inputter;

您不需要单独将FileInput/OutputStreams 作为数据成员。删除。

    // initialiserar databasen
    public void init() {
        // checkar om filen existerar och isåfall assignar inputter och outputter till filen
        System.out.println(currentFile.exists() && !currentFile.isDirectory());
        if (currentFile.exists() && !currentFile.isDirectory()) {
            try {
                OutPutter = new FileOutputStream(currentFile);
                OutPutter.flush();
                Inputter = new FileInputStream(currentFile);
                OutputStream = new ObjectOutputStream(OutPutter);
                OutputStream.flush();
                InputStream = new ObjectInputStream(Inputter);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            // annars så skapar den filen och assignar det istället
            try {
                boolean temp1 = currentFile.getParentFile().mkdirs();
                boolean temp2 = currentFile.createNewFile();
                if (temp2) {
                    OutPutter = new FileOutputStream(currentFile);
                    Inputter = new FileInputStream(currentFile);
                    OutputStream = new ObjectOutputStream(OutPutter);
                    InputStream = new ObjectInputStream(Inputter);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

您可以减少所有复杂的双向对话:

try {
    currentFile.getParentFile().mkdirs();
    OutputStream = new ObjectOutputStream(new FileOutputStream(currentFile));
    InputStream = new ObjectInputStream(new FileInputStream(currentFile));
} catch (IOException exc) {
    exc.printStackTrace();
}

...尽管如果 init() 抛出 IOException 而不是在内部捕获并吸收它会更好。您编写的所有复杂代码仅完成此任务。同时打开文件进行输出和输入确实没有意义,并且在某些平台(例如 Windows)上不起作用。您需要重新考虑这一点。

    public void write() {
        try {
            PrintWriter n = new PrintWriter(currentFile);
            n.close();

问题就出在这里。 PrintWriter 未使用,因此应该将其删除,但这里真正的问题是您刚刚截断了输出文件,当通过 ObjectInputStream 读取它时,肯定会产生 IOException。删除。

    public void close() {
        try {
            OutPutter.close();
            Inputter.close();
            InputStream.close();
            OutputStream.flush();
            OutputStream.close();

这都是废话。 close()之前的flush()是多余的,只需关闭InputStreamOutputStream即可。他们将为您关闭嵌套流,即使他们没有这样做,关闭嵌套输出流并然后尝试刷新并关闭外部输出流也是没有意义的。

        } catch (Exception e) {
            e.printStackTrace();
        }

同样,该方法应该抛出IOException,而不是吸收它。

    public long getFileSize() {
        return currentFile.length();
    }

这实在是太没有意义了。在某些操作系统(例如 Windows)上,在关闭文件之前目录条目不会更新,因此您可能只是在此处返回零。您不需要知道文件的当前长度。

        try {
            if (InputStream.read() != -1) {

这没有任何意义。这里你读了一个字节并把它扔掉了。由于您没有写入任何额外的字节,这只会使您与流不同步。删除这个。

                data = (NavigableMap) InputStream.readObject();
            } else {
                data = new TreeMap<>();
                System.out.println(data);
            }

这个“其他”也没有任何意义。如果文件为空或不再包含任何对象,则会抛出 EOFException,此时您应该采取任何规避操作。事实上,您应该再一次让各种 IOExceptions 在这里抛出,而不是无意义地替换一个空的 TreeMap

        } catch (Exception e) {
            e.printStackTrace();
        }

参见上面重新抛出IOException。不要编写这样的代码。

    public void closeAndWrite() {

如果您确实需要此方法,则应将其命名为 writeAndClose(),但您并不需要。

I have checked the file in question and it does indeed contain a serialized Treemap.

怎么查的?只有一种方法可以检查这一点,那就是调用 readObject()

关于java - 读取包含对象的文件时,ObjectInputStream 抛出 EOFException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41091194/

相关文章:

java - append 到 ObjectOutputStream

java - 在关机时停止所有 Spring 批处理作业 (CTRL-C)

java - 为什么我无法使用 SnakeYaml 和 Lombok 解析 yaml 字符串?

java - 声明来自套接字的输入/输出流以防止程序继续

java - ObjectOutputStream - 客户端/服务器通信

java - JsonInclude.Include.NON_DEFAULT 不适用于自定义序列化程序

java - Android viewBinder 在 simpleCursorAdapter 上显示图像

java - 如何处理具有相同 xpath 的多个对象的动态变化 xpath

java - 我想写入和读取文件,当我运行 : java. io.EOFException 时出现此错误

java - Kryo序列化错误