从一个千兆字节的文件中读取

IUn*_*own 1 java file-io fileinputstream

对于大型文件或管道流,缓冲支持的解决方案(BufferedInputStream/ByteArrayInputStream)显然不是可行的方法.如果有人能告诉我处理这种情况的推荐方法,我将不胜感激.

我可以想到这一点 - 但可能不是那里最好或最有效的方法:

public class Streams {
  public static void main(String[] args) throws IOException {
    DataInputStream reader=null;
    try{
      try {
        reader=new DataInputStream(new FileInputStream("/path/file"));
      } catch (FileNotFoundException e1) {
        throw e1;
      }
      while(true) {
        try {
          byte a=reader.readByte();
        } 
        catch(EOFException e) {
          //consume
        }
        catch (IOException e) {
          //throw
          throw e;
        }
        //do something
      }
    }
    finally {
      try {
        reader.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*n C 6

使用BufferedInputStreamBufferedReader用于大文件没有任何根本性的错误.实际上,如果您需要一次读取/处理文件一个字节或字符,这是一种自然的方法.如果您在读取它们后对字节/字符执行了大量"工作"(即此应用程序的瓶颈不是读取输入流),那么缓冲流可能就好了.

另一方面,使用a ByteArrayInputStream是一个糟糕的选择有两个原因:

  • 您需要先将整个文件加载(或映射)到内存中,然后才能创建ByteArrayInputStream.
  • 在字节数组的大小上有2 ^ 31字节的上限...即2Gb.

事实上,你提出的a版本与使用a DataInputStream没有实质性的不同BufferedInputStream.A DataInputStream使用内部缓冲区的方式与使用内部缓冲区的方式大致相同BufferedInputStream.

我的记忆不正确.实际上DataInputStream.readByte()是无缓冲的.因此,您建议的版本将比使用的版本慢很多BufferedInputStream.基本上,readByte()您的版本中的每个调用都将执行一个系统调用.这将使阅读变得非常非常缓慢.


您可以获得显着加速的唯一方法是使用NIO BufferChannelAPI 读取文件.与传统API相比,这些API减少了内存中复制的数量.缺点是这些API使用起来更加笨拙.

这预示着读取输入文件主要的瓶颈.