使用缓冲区读取二进制文件

问题描述 投票:1回答:1

我正在尝试读取包含100.000个不同对象的二进制文件。 使用相同的内容缓冲一个简单的文本文件,使用BufferedReader只需2MB。

但是读取二进制文件最多需要700 MB,如果增加要读取的对象数,我会出现OutOfMemory错误。

那么如何在不使内存饱和的情况下逐个读取文件并获取对象呢?

这是我正在测试的代码:

public static void main(String[] args) throws Exception {
    int i = 0;
    String path = "data/file.bin";
    InputStream file = new FileInputStream(path);
    InputStream buffer = new BufferedInputStream(file);
    ObjectInputStream in = new ObjectInputStream(buffer);
    Object obj = null;
    while( ( obj = in.readObject() ) != null && i < 100000 ){
        String str =  obj.toString();
        System.out.println( str );
        i++;
    }

    timeTkken();
}

// Function to get the amount of time/memory used by the script
private static final long startTime = System.currentTimeMillis();
private static final long MEGABYTE = 1024L * 1024L;
public static void timeTkken(){
    Runtime runtime = Runtime.getRuntime();
    long endTime = System.currentTimeMillis();
    long memory = runtime.totalMemory() - runtime.freeMemory();
    long megabytes = memory / MEGABYTE;
    System.out.println("It took " + megabytes + "mb in " + ( (endTime - startTime) /1000 ) + "s ("+ memory + (" bytes in ") + (endTime - startTime) + " ms)");

}
java buffer inputstream binaryfiles
1个回答
2
投票

据我所知,ObjectInputStream将所有对象保留在缓存中,直到流关闭。因此,如果你的二进制文件大约是207 MB,那么java堆中的真实对象可能很容易占用几GB的RAM而且它们不能被垃圾收集。这里出现的问题是:您是否需要同时将所有数据保存在RAM中?

如果不是(你想要读取一个对象,以某种方式处理它,丢弃它并移动到下一个对象),我建议使用DataInputStream而不是ObjectInputStream。我不知道这种方法是否适用于您的情况,因为我不知道您的数据结构。如果您的数据是相同结构的记录集合,则可以执行以下操作:

    public class MyObject {
        private int age;
        private String name;

        public MyObject(int age, String name) {
            this.age = age;
            this.name = name;
        }
    }

    DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("path.to.file")));
    // suppose that we store the total number of objects in the first 4 bytes of file
    int nObjects = in.readInt();
    for (int i = 0; i < nObjects; i++) {
        MyObject obj = new MyObject(in.readInt(), in.readUTF());
        // do some stuff with obj
    }
© www.soinside.com 2019 - 2024. All rights reserved.