问题描述
我正在尝试创建一个程序,该程序读取包含.dat
对象的HashMap
文件。如果.dat
文件为空,则应向该文件写入一个空的HashMap
对象,然后,应为用户提供编辑HashMap
对象的选项。
当我第一次使用一个空的.dat
文件“ playlist.dat”尝试此操作时,它试图将一个空的HashMap
对象写入该文件,但随后触发了一个{{1} }。我查看了文件,发现它是空的。
此处处理代码:
EOFException
解决方法
几件事:
-
对象流非常脆弱,并不理想。使用不同版本的Java的用户可能无法以不同于序列化版本的版本打开HashMap。相反,我建议使用XML(已包含在JRE中)或JSON(我相信您需要Jackson库...除非已将其添加到JRE中)
-
您不需要缓冲输入或输出流。首先,缓冲流用于低效的读取和写入(例如逐行读取或写入(并非一次全部)到File。但是对象流和PrintWriter / PrintStream(不是)使用,但出于完整性考虑,我已经将其包括在内)已经具有缓冲能力。
-
在尝试从流中读取之前,应绝对关闭写入流。我相信如果/当您这样做时,在阅读文件时会看到文件中的内容
BufferedOutputStream
的内部缓冲区的大小等于 8192字节。直到数据超过缓冲区或您刷新,将整个数据保存在缓冲区中,这样才不会将其写入文件
似乎播放列表数据小于缓冲区大小-写入完成后,您需要在close()
输出流上调用out
方法,或使用try-with-resources方法
基本上,您想要serialize一个对象,特别是HashMap
的一个实例,然后反序列化它。
Java中的序列化仅存储类成员的值。它使用实际的.class
文件和.dat
文件的组合来反序列化对象。因此,如果序列化一个空的HashMap
,则.dat
文件将几乎为空。您的情况是空的,因为您没有在写入文件后关闭文件。
下面的代码是对HashMap
进行序列化和反序列化的最小示例。请注意,它使用try-with-resources来确保.dat
文件在使用后关闭。它还使用multi-catch处理异常。
代码说明出现在其后。
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
public class SongList {
public static void main(String[] args) {
File f = new File("songlist.dat");
try (FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
HashMap<String,String> playList = new HashMap<>();
oos.writeObject(playList);
}
catch (IOException xIo) {
xIo.printStackTrace();
}
try (FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis)) {
HashMap<?,?> playList = (HashMap<?,?>) ois.readObject();
}
catch (IOException | ClassNotFoundException x) {
x.printStackTrace();
}
}
}
-
BufferedOutputStream
和BufferedInputStream
不是必需的。 - 在运行时,当对
HashMap
进行反序列化时,java无法知道HashMap
中条目的类型。这就是为什么您会收到警告。请注意,这只是警告而不是错误。这就是为什么我在读取?
文件时使用.dat
通配符的原因。 - 由于您没有发布类
Song
的代码,因此我将HashMap
的值类型更改为String
,以使事情变得简单。您可以继续在代码中使用Song
。 - 创建新的
FileOutputStream
会创建一个新的空文件。为已存在的文件创建新的FileOutputStream
将删除文件内容。如果要附加到现有文件,请使用类FileOutputStream
的{{3}}。
顺便说一句,您不应该关闭包装标准输入的Scanner
。