对于大型文件或管道流,缓冲区支持的解决方案(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();
}
}
}
}
答案 0 :(得分:6)
对大文件使用BufferedInputStream
或BufferedReader
没有任何根本性的错误。实际上,如果您需要一次读取/处理文件一个字节或字符,这是一种自然的方法。如果您在读取它们后对字节/字符执行了大量“工作”(即此应用程序的瓶颈不是读取输入流),那么缓冲流可能就好了。
另一方面,使用ByteArrayInputStream
是一个糟糕的选择,原因有两个:
ByteArrayInputStream
。 事实上,您使用 DataInputStream
的建议版本与使用BufferedInputStream
没有什么不同。 DataInputStream
使用内部缓冲区的方式与BufferedInputStream
的方式非常相似。
我的记忆不正确。实际上DataInputStream.readByte()
是无缓冲的。因此,您建议的版本将比使用BufferedInputStream
的版本慢得多。基本上,您的版本中的每个readByte()
调用都会进行一次系统调用。这将使阅读变得非常非常缓慢。
获得显着加速的唯一方法是使用NIO Buffer
和Channel
API读取文件。与传统API相比,这些API减少了内存中复制的数量。缺点是这些API使用起来更加笨拙。
这预先假定读取输入文件是的主要瓶颈。
答案 1 :(得分:2)
将FileInputStream
包裹在BufferedInputStream
中没有问题。根据Java库源代码,默认缓冲区大小仅为8192字节,因此使用它不会耗尽内存。
在您当前的代码中,DataInputStream.readByte()
的每次调用都会调用FileInputStream.read()
,这是一个缓慢的本机函数,可以转到C和操作系统。
相反,您应该将FileInputStream
包装在缓冲区大小为几百KB的BufferedInputStream
中。这样,DataInputStream.readByte()
将调用BufferedInputStream.read()
,这相当快(并且使用纯Java实现)。