面试题答案
一键面试理论分析
- FileInputStream:
- 每次调用
read
方法,都会直接从文件系统中读取数据,这涉及到用户态到内核态的切换以及磁盘I/O操作。磁盘I/O相对内存操作来说非常慢,频繁的系统调用会增加额外的开销,导致读取大文件时性能较低。
- 每次调用
- BufferedInputStream:
- 内部有一个缓冲区(默认大小为8192字节)。首次调用
read
方法时,它会一次性从文件系统中读取一批数据到缓冲区,后续的read
操作优先从缓冲区获取数据。只有当缓冲区数据读完时,才会再次从文件系统读取数据填充缓冲区。这样减少了磁盘I/O操作的次数和用户态到内核态的切换次数,从而提高了读取性能。
- 内部有一个缓冲区(默认大小为8192字节)。首次调用
实际代码测试
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class FileReadPerformanceTest {
public static void main(String[] args) {
String filePath = "largeFile.txt";
long startTime, endTime;
// 使用FileInputStream测试
startTime = System.currentTimeMillis();
try (FileInputStream fis = new FileInputStream(filePath)) {
int data;
while ((data = fis.read()) != -1) {
// 简单处理,这里可以是实际业务处理
}
} catch (IOException e) {
e.printStackTrace();
}
endTime = System.currentTimeMillis();
System.out.println("FileInputStream读取时间: " + (endTime - startTime) + " ms");
// 使用BufferedInputStream测试
startTime = System.currentTimeMillis();
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath))) {
int data;
while ((data = bis.read()) != -1) {
// 简单处理,这里可以是实际业务处理
}
} catch (IOException e) {
e.printStackTrace();
}
endTime = System.currentTimeMillis();
System.out.println("BufferedInputStream读取时间: " + (endTime - startTime) + " ms");
}
}
通常情况下,运行上述代码会发现BufferedInputStream
的读取时间明显短于FileInputStream
。
缓冲流提升效率的关键因素
- 减少系统调用次数:通过缓冲区,减少了对底层文件系统的直接读取次数,从而减少了用户态到内核态的切换次数,降低了系统开销。
- 批量读取数据:一次性从文件系统读取较大的数据块到缓冲区,利用了磁盘I/O的批量传输特性,提高了数据传输效率。
- 内存操作优势:从缓冲区读取数据是内存操作,内存访问速度远快于磁盘I/O,在缓冲区数据未读完时,能快速提供数据给应用程序,提升整体性能。