英文:
Java: OutOfMemory exception when trying to read objects from a very large file
问题
以下是您要求的翻译部分:
我已经使用下面的代码将近10,000个对象保存在文件中:
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);
现在,当我尝试读取文件时,会抛出内存不足异常。我该如何解决这个问题。以下是读取对象的代码:
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;
我之所以想要读取所有对象,是因为我想在表格视图中显示所有数据,所以我需要将所有(10,000行)添加到数组列表中并显示在表格视图中。
是否有任何选项可以限制readObject()
方法,以便它只能从非常大的文件中检索出少量对象。
我该如何改进这个?请帮忙指导。
英文:
I have saved almost 10k objects in a file using this code below:
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);
Now when I'm trying to read the file it is throwing OutOfMemory exception. How I can resolve this. Below is the code for reading objects.
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;
The reason i want to read all objects is I want to show all the data in tableview so i need to add all the (10k rows) into arraylist and show it on tableview.
Is there any option to limit the readObject(), so it can only retrieve few objects from a very large file.
How I can improve this? Please help.
答案1
得分: 0
你正在一次性对整个集合进行序列化和反序列化。如果你写入各个对象(而不是包含的 ArrayList
),就能够一次性读取一个范围。
英文:
You're serializing and deserializing the entire collection in one go. If you write the individual objects (rather than the containing ArrayList
) you'd be able to read a range at a time.
答案2
得分: 0
你在这里的情况有些棘手。
看起来你已经将所有的对象放入一个列表中,然后使用单个writeObject
调用将该列表保存到文件中。
如果你这样做,那么你实际上没有其他选择,只能将整个列表读回来。我猜,或许你可以实现一个“hack”(使用自定义的读取对象方法或类似方法)将不需要的DeviceInfo
对象“读取”为null
以节省空间。但这可能会带来一些不利影响。
一个解决方案是通过逐个序列化元素来序列化原始列表。然后你可以逐个读取它们,忽略掉你不想要的部分。虽然这并不高效,但你应该能够避免用那些当前不需要的对象填充堆内存。
一个更好的解决方案是使用另一种保存数据的方法:
-
你可以使用关系型数据库(RDBMS)、NoSQL数据库或者类似BerkleyDB的平面文件数据库,然后只选择你想要显示的行。
-
你可以使用另一种序列化格式,比如JSON、XML或CSV,它们具有流式API。然后你可以流式地读取整个文件,只实例化你想要显示的元素。
某种类型的数据库可能是更好的选择。
英文:
You are kind of stuffed here.
It looks like you have put all of the objects into a list and then saved the list to the file using a single writeObject
call.
If you do that, you don't have any real choice but to read back the entire list. I guess, conceivably, you could implement a hack (with custom read object methods or similar) to "read" the unwanted DeviceInfo
objects as null
to save space. But that is liable to have down-sides.
One solution is to serialize the original list by serializing the elements individually. Then you can read them back one at a time, and ignore the ones that you don't want. It is not efficient, but you should be able to avoid filling the heap with objects that are not currently needed.
A better solution would be to use another method of saving the data:
-
You could use an RDBMS, a NoSQL database or a flat-file database (like BerkleyDB) and select just the rows that you want to display.
-
You could use another serialization format such as JSON, XML or CSV which has a streaming API. Then you stream the entire file and only reify the elements you want to display.
A database of some kind would be preferable.
答案3
得分: -1
为了从文件中读取10,000个对象,请尝试使用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);
}
// 注意,Scanner会压制内存不足异常
if (scanner.ioException() != null) {
throw scanner.ioException();
}
} finally {
if (fInputStream != null) {
fInputStream.close();
}
if (scanner != null) {
scanner.close();
}
}
以上代码将帮助在不用迭代方式、不耗尽可用内存的情况下处理一个大文件中的行(每行一个对象)。
英文:
In order to read 10k objects from a file please try to use 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();
}
}
The above code will help to process lines(one object each line) in a large file without iteratively, without exhausting the available memory.
专注分享java语言的经验与见解,让所有开发者获益!
评论