面试题答案
一键面试缓冲流提高输入输出性能的原理
- 减少系统调用次数:
BufferedInputStream
和BufferedOutputStream
内部都有一个缓冲区(字节数组)。例如BufferedInputStream
在读取数据时,不是每次都从底层输入流(如文件流)中读取单个字节,而是一次性从底层输入流读取多个字节到缓冲区中。当程序调用read()
方法读取数据时,首先从缓冲区中获取数据。只有当缓冲区中的数据读完后,才会再次从底层输入流中填充缓冲区。- 对于
BufferedOutputStream
,调用write()
方法时,数据先写入缓冲区,而不是直接写入底层输出流。当缓冲区满或者调用flush()
方法时,才将缓冲区中的数据一次性写入到底层输出流。这样大大减少了对底层输入输出设备的系统调用次数,因为系统调用通常是比较耗时的操作,从而提高了输入输出性能。
- 数据批量传输:
- 由于缓冲区可以批量读取或写入数据,相比每次读取或写入单个字节,减少了数据传输的开销。例如,从文件读取数据,如果没有缓冲区,每次读取一个字节都要与文件系统交互,而使用
BufferedInputStream
可以一次读取多个字节到缓冲区,然后程序从缓冲区中顺序获取数据,减少了与文件系统的交互次数。
- 由于缓冲区可以批量读取或写入数据,相比每次读取或写入单个字节,减少了数据传输的开销。例如,从文件读取数据,如果没有缓冲区,每次读取一个字节都要与文件系统交互,而使用
使用缓冲流时的注意事项
- 及时关闭流:
- 缓冲流使用完后必须关闭,否则可能会导致资源泄漏。不仅要关闭缓冲流,还要关闭其底层的流。例如,
BufferedInputStream
可能包装了一个FileInputStream
,关闭BufferedInputStream
时会自动关闭其底层的FileInputStream
,但为了代码的清晰和规范,建议手动先关闭缓冲流,再关闭底层流。
- 缓冲流使用完后必须关闭,否则可能会导致资源泄漏。不仅要关闭缓冲流,还要关闭其底层的流。例如,
- 注意缓冲区大小:
- 缓冲流构造函数可以指定缓冲区大小。默认情况下,
BufferedInputStream
和BufferedOutputStream
的缓冲区大小是8192字节(8KB)。在某些场景下,如果数据量非常大或者系统资源有限,可以根据实际情况调整缓冲区大小。例如,在处理超大文件时,适当增大缓冲区大小可能会进一步提高性能,但同时也会占用更多内存。
- 缓冲流构造函数可以指定缓冲区大小。默认情况下,
- flush操作:
- 对于
BufferedOutputStream
,在数据写入缓冲区后,需要调用flush()
方法将缓冲区的数据真正写入到底层输出流。特别是在程序结束前,如果没有调用flush()
方法,可能会导致部分数据留在缓冲区中未被写入。例如,在网络编程中向服务器发送数据时,如果不flush
,服务器可能无法及时收到完整的数据。
- 对于
代码示例
- 使用
BufferedInputStream
读取文件:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class BufferedInputStreamExample {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("example.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
int data;
while ((data = bufferedInputStream.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 使用
BufferedOutputStream
写入文件:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class BufferedOutputStreamExample {
public static void main(String[] args) {
String content = "This is an example of using BufferedOutputStream.";
try (OutputStream outputStream = new FileOutputStream("output.txt");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
byte[] data = content.getBytes();
bufferedOutputStream.write(data);
bufferedOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在上述BufferedOutputStream
的示例中,flush()
方法确保了数据从缓冲区写入到文件中。如果不调用flush()
方法,数据可能会留在缓冲区中,导致文件内容不完整。在BufferedInputStream
的示例中,通过缓冲区,减少了从文件系统读取数据的次数,提高了读取效率。