Java 为什么使用BufferedInputStream逐字节读取文件比使用FileInputStream快?
我试图使用FileInputStream将一个文件读入数组,一个~800KB的文件读入内存大约需要3秒钟。然后,我尝试了相同的代码,只是将FileInputStream包装到BufferedInputStream中,耗时约76毫秒。为什么使用BufferedInputStream一个字节一个字节地读取文件要快得多,即使我仍在一个字节一个字节地读取它?下面是代码(其余代码完全无关)。请注意,这是“快速”代码。如果需要“慢速”代码,可以删除BufferedInputStream:Java 为什么使用BufferedInputStream逐字节读取文件比使用FileInputStream快?,java,file-io,inputstream,fileinputstream,Java,File Io,Inputstream,Fileinputstream,我试图使用FileInputStream将一个文件读入数组,一个~800KB的文件读入内存大约需要3秒钟。然后,我尝试了相同的代码,只是将FileInputStream包装到BufferedInputStream中,耗时约76毫秒。为什么使用BufferedInputStream一个字节一个字节地读取文件要快得多,即使我仍在一个字节一个字节地读取它?下面是代码(其余代码完全无关)。请注意,这是“快速”代码。如果需要“慢速”代码,可以删除BufferedInputStream: BufferedI
BufferedInputStream的速度快30倍以上。远不止这些。那么,这是为什么呢?有没有可能使此代码更高效(不使用任何外部库)?在
FileInputStream
中,方法read()
读取单个字节。从源代码:
/**
* Reads a byte of data from this input stream. This method blocks
* if no input is yet available.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* file is reached.
* @exception IOException if an I/O error occurs.
*/
public native int read() throws IOException;
这是对使用磁盘读取单个字节的操作系统的本机调用。这是一项繁重的行动
使用BufferedInputStream
,该方法将委托给重载的read()
方法,该方法读取8192
字节量,并将它们缓冲到需要为止。它仍然只返回单个字节(但保留其他字节)。这样,BufferedInputStream
就减少了对操作系统的本机调用以读取文件
例如,您的文件长度为32768字节。要使用FileInputStream
获取内存中的所有字节,需要对操作系统进行32768
本机调用。使用BufferedInputStream
,无论要执行多少次read()
调用(仍然32768
),您只需要4
)
<>如何加快速度,你可能想考虑java 7的Nio>代码>文件通道< /C>类,但是我没有证据支持这个。
注意:如果直接使用
FileInputStream
的读取(byte[],int,int)
方法,而使用byte[>8192]
则不需要BufferedInputStream
包装它。围绕FileInputStream包装的BufferedInputStream将以大块的形式从FileInputStream请求数据(我认为默认情况下大约512字节。)因此,如果您一次读取1000个字符,FileInputStream只需进入磁盘两次。这将快得多!这是因为磁盘访问的成本。让我们假设您将拥有一个大小为8kb的文件。在没有BufferedInputStream的情况下,需要8*1024倍的访问磁盘才能读取此文件
此时,BufferedStream进入场景并充当FileInputStream和要读取的文件之间的中间人
在一个快照中,将获取字节块,默认值为8kb到内存,然后FileInputStream将从这个中间人读取字节。
这将缩短操作时间
private void exercise1WithBufferedStream() {
long start= System.currentTimeMillis();
try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(myFile);
boolean eof = false;
while (!eof) {
int inByteValue = bufferedInputStream.read();
if (inByteValue == -1) eof = true;
}
} catch (IOException e) {
System.out.println("Could not read the stream...");
e.printStackTrace();
}
System.out.println("time passed with buffered:" + (System.currentTimeMillis()-start));
}
private void exercise1() {
long start= System.currentTimeMillis();
try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
boolean eof = false;
while (!eof) {
int inByteValue = myFile.read();
if (inByteValue == -1) eof = true;
}
} catch (IOException e) {
System.out.println("Could not read the stream...");
e.printStackTrace();
}
System.out.println("time passed without buffered:" + (System.currentTimeMillis()-start));
}
啊,我明白了,我应该在询问之前先检查API。所以它只是一个8K的内部缓冲区。这很有意义。谢谢。至于“更高效”部分,这是不必要的,但我认为我的代码在某种程度上可能过于冗余。我想不是。@user1007059不客气。请注意,如果使用
FileInputStream
的read(byte[],int,int)
方法,直接使用byte[>8192]
你不需要一个BufferedInputStream
包装它。@SotiriosDelimanolis何时使用read()
逐字节,何时使用read(byte[])
字节数组。我认为读取数组总是更好。那么你能给我一个例子,在哪里使用read()
逐字节或read(byte[])
byte数组。或者BufferedInputStream
?@UnKnown没有一个很好的例子。可能第一个字节包含一些关于文件内容的标志或其他元数据。我认为任何人都不会使用read()读取整个文件
@emilyBufferedInputStream
在代码请求读取更少字节(不一定只有一个字节)时速度更快每次都比缓冲区大小大。BufferedInputStream
表现乐观,读取的数据比您需要的要多,因此,当您返回时,它已经有了下一批数据。可能是,但对于大多数平台来说都是。8K相同。这个示例很好。但是,用这样的数据检查执行时间-基准测试绝对不正确例如,使用JMH来正确检查。
private void exercise1WithBufferedStream() {
long start= System.currentTimeMillis();
try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(myFile);
boolean eof = false;
while (!eof) {
int inByteValue = bufferedInputStream.read();
if (inByteValue == -1) eof = true;
}
} catch (IOException e) {
System.out.println("Could not read the stream...");
e.printStackTrace();
}
System.out.println("time passed with buffered:" + (System.currentTimeMillis()-start));
}
private void exercise1() {
long start= System.currentTimeMillis();
try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
boolean eof = false;
while (!eof) {
int inByteValue = myFile.read();
if (inByteValue == -1) eof = true;
}
} catch (IOException e) {
System.out.println("Could not read the stream...");
e.printStackTrace();
}
System.out.println("time passed without buffered:" + (System.currentTimeMillis()-start));
}