Java:OutOfMemory异常,当尝试从一个非常大的文件中读取对象时



我使用以下代码在一个文件中保存了近10k个对象:

boolean exists = Tools.getDeviceInfo().exists();
FileOutputStream fos = new FileOutputStream(Tools.getDeviceInfo(), true);
ObjectOutputStream oos = exists ?
new ObjectOutputStream(fos) {
protected void writeStreamHeader() throws IOException {
reset();
}
}:new ObjectOutputStream(fos);
oos.writeObject(deviceInfos);

现在,当我试图读取文件时,它抛出了OutOfMemory异常。我该如何解决这个问题。下面是读取对象的代码。

FileInputStream fis = new FileInputStream(Tools.getDeviceInfo());
ObjectInputStream ois = new ObjectInputStream(fis);
ArrayList<DeviceInfo> arrayList = new ArrayList<>();
try {
arrayList.addAll((ArrayList<DeviceInfo>)ois.readObject());
} catch (Exception e) {
e.printStackTrace();
}
ois.close();
return arrayList;

我想读取所有对象的原因是我想在tableview中显示所有数据,所以我需要将所有(10k行(添加到arraylist中,并在tableview上显示。是否有任何选项可以限制readObject((,使其只能从一个非常大的文件中检索几个对象。我该如何改进?请帮忙。

您正在一次性序列化和反序列化整个集合。如果您编写单独的对象(而不是包含的ArrayList(,您将能够一次读取一个范围。

你在这里有点塞。

看起来您已经将所有对象放入一个列表中,然后使用一个writeObject调用将列表保存到文件中。

如果你这样做了,你别无选择,只能读回整个列表。我想,可以想象,您可以实现一个破解(使用自定义读取对象方法或类似方法(,将不需要的DeviceInfo对象"读取"为null,以节省空间。但这可能会带来负面影响。

一种解决方案是通过单独序列化元素来序列化原始列表。然后你可以一次读一个,忽略那些你不想要的。它效率不高,但应该能够避免用当前不需要的对象填充堆。

更好的解决方案是使用另一种保存数据的方法:

  • 您可以使用RDBMS、NoSQL数据库或平面文件数据库(如BerkleyDB(,然后只选择要显示的行。

  • 您可以使用其他序列化格式,如JSON、XML或CSV,这些格式具有流式API。然后流式传输整个文件,只具体化要显示的元素。

最好使用某种数据库。

要从文件中读取10k个对象,请尝试使用java.util.scanner

FileInputStream fInputStream = null;
Scanner scanner = null;
try {
fInputStream = new FileInputStream(path);//file path
scanner = new Scanner(fInputStream, "UTF-8");
ArrayList<DeviceInfo> arrayList = new ArrayList<>();
while (scanner.hasNextLine()) {
DeviceInfo dObj = new DeviceInfo();
dObj = scanner.nextLine();
arrayList.addall(dObj);
}
// note that Scanner suppresses out of memory exception
if (scanner.ioException() != null) {
throw scanner.ioException();
}
} finally {
if (fInputStream != null) {
fInputStream.close();
}
if (scanner != null) {
scanner.close();
}
}

上面的代码将有助于在不迭代的情况下处理大文件中的行(每行一个对象(,而不会耗尽可用内存。

相关内容

最新更新