1

对于大文件或管道流,缓冲区支持的解决方案 (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();
      }
    }
  }
}
4

2 回答 2

6

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

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

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

事实上,您提议的带有 a 的版本与使用 aDataInputStream没有本质区别BufferedInputStream。ADataInputStream使用内部缓冲区的方式与 a 大致相同BufferedInputStream

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


获得显着加速的唯一方法是使用 NIOBufferChannelAPI 读取文件。与经典 API 相比,这些 API 减少了发生的内存复制量。缺点是这些 API 使用起来更尴尬。

这假设读取输入文件主要瓶颈。

于 2013-08-18T04:41:45.470 回答
2

FileInputStream将 包装在中没有问题BufferedInputStream。根据 Java 库源代码,默认缓冲区大小仅为 8192 字节,因此您不会因为使用它而耗尽内存。

在您当前的代码中,每次调用都DataInputStream.readByte()将调用FileInputStream.read(),这是一个慢速的本地函数,用于 C 和操作系统。

相反,您应该用几百 KB 的缓冲区大小将其包装FileInputStream在 a中。BufferedInputStream这样,DataInputStream.readByte()将调用BufferedInputStream.read()相当快(并在纯 Java 中实现)。

于 2013-08-18T04:39:31.870 回答