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

Java 用缓冲区读取二进制文件,java,buffer,inputstream,binaryfiles,Java,Buffer,Inputstream,Binaryfiles,我正在尝试读取包含100000个不同对象的二进制文件。 使用BufferedReader缓冲具有相同内容的简单文本文件只需2MB 但是读取二进制文件需要高达700MB的空间,如果我增加要读取的对象的数量,就会出现内存错误 那么,如何读取文件并逐个获取对象而不使内存饱和呢 以下是我正在测试的代码: public static void main(String[] args) throws Exception { int i = 0; String path = "data/file

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

但是读取二进制文件需要高达700MB的空间,如果我增加要读取的对象的数量,就会出现内存错误

那么,如何读取文件并逐个获取对象而不使内存饱和呢

以下是我正在测试的代码:

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)");

}
publicstaticvoidmain(字符串[]args)引发异常{
int i=0;
String path=“data/file.bin”;
InputStream文件=新文件InputStream(路径);
InputStream buffer=新的BufferedInputStream(文件);
ObjectInputStream in=新的ObjectInputStream(缓冲区);
objectobj=null;
而((obj=in.readObject())!=null&&i<100000){
字符串str=obj.toString();
系统输出打印项次(str);
i++;
}
timeTkken();
}
//函数获取脚本使用的时间/内存量
私有静态最终长startTime=System.currentTimeMillis();
专用静态最终长MB=1024L*1024L;
公共静态void timeTkken(){
Runtime=Runtime.getRuntime();
long-endTime=System.currentTimeMillis();
长内存=runtime.totalMemory()-runtime.freemory();
长兆字节=内存/兆字节;
System.out.println(“需要”+((endTime-startTime)/1000)s中的“+mb+”mb(“+memory+(“bytes in”)+(endTime-startTime)+“ms”);
}

据我所知,
ObjectInputStream
将所有对象保留在缓存中,直到流关闭。所以,如果您的二进制文件是~207MB,那么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
    }
公共类MyObject{
私人互联网;
私有字符串名称;
公共MyObject(整数,字符串名){
这个。年龄=年龄;
this.name=名称;
}
}
DataInputStream in=新的DataInputStream(新的BufferedInputStream(新的FileInputStream(“path.to.file”)));
//假设我们在文件的前4个字节中存储对象的总数
int nObjects=in.readInt();
for(int i=0;i
这两个文件的原始大小是多少?磁盘上的二进制文件是207 MB,文件的文本版本是232 MB。您是否有可能更改为与Java序列化不同的数据格式?它不是很有用,它很脆弱,而且由于它在内部的工作方式,它可以在内存中保存很多您甚至不需要的东西(引用早期序列化对象,我怀疑这是这里的问题)。是的,问题是它在内存中保存的stuf,有没有更好的方法来处理java中的二进制文件?初学者最糟糕的事情就是担心性能。我一直在问题中看到这一点。一个初露头角的程序员想知道
i++
是否比
++i
快,把时间浪费在完全不相关的事情上。性能是一个高级问题,在掌握基本技能和更广泛地了解软件如何工作以及性能在何处起作用之前,您不应该过多地担心它。您在这里提出的建议几乎就是我所需要的,我必须一次处理一个对象,并清除可能留在RAM中的任何缓存,“我的文件”包含不同类型的对象列表,其中大多数是列表
list
。因此,如果我可以在.readObject()中执行
而不缓存任何内容,那就太好了,我会试试你code@zakaria35您不能使用“ObjectInputStream.readObject()”一次读取一个对象-您需要使用DataInputStream,读取原始原语和字符串,并重建对象。