Java BufferedInputStream
外观
Java BufferedInputStream[编辑 | 编辑源代码]
BufferedInputStream是Java I/O库中提供的一个带有缓冲功能的输入流类,通过减少底层系统的实际读取操作次数来提高I/O效率。它继承自`FilterInputStream`,属于装饰器模式(Decorator Pattern)的典型应用。
核心原理[编辑 | 编辑源代码]
数学上,设单次系统调用耗时为,缓冲区大小为字节,则读取字节数据的理论耗时从降低至
构造函数[编辑 | 编辑源代码]
提供两种主要构造方式:
// 方式1:使用默认缓冲区大小(通常8192字节)
InputStream fis = new FileInputStream("test.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
// 方式2:自定义缓冲区大小
BufferedInputStream bisCustom = new BufferedInputStream(fis, 16384); // 16KB缓冲区
核心方法[编辑 | 编辑源代码]
方法 | 描述 |
---|---|
`int read()` | 读取单个字节,返回-1表示EOF |
`int read(byte[] b, int off, int len)` | 读取到字节数组的指定位置 |
`long skip(long n)` | 跳过指定字节数 |
`void mark(int readlimit)` | 设置标记点 |
`void reset()` | 返回到标记点 |
`boolean markSupported()` | 是否支持标记(BufferedInputStream返回true) |
性能对比示例[编辑 | 编辑源代码]
测试读取100MB文件的耗时差异:
public class PerformanceTest {
static void readWithoutBuffer() throws IOException {
try (InputStream is = new FileInputStream("largefile.bin")) {
long start = System.nanoTime();
while (is.read() != -1); // 逐字节读取
System.out.printf("无缓冲耗时: %.2fms\n", (System.nanoTime()-start)/1e6);
}
}
static void readWithBuffer() throws IOException {
try (InputStream is = new BufferedInputStream(new FileInputStream("largefile.bin"))) {
long start = System.nanoTime();
while (is.read() != -1); // 通过缓冲读取
System.out.printf("缓冲耗时: %.2fms\n", (System.nanoTime()-start)/1e6);
}
}
}
典型输出结果:
无缓冲耗时: 4520.17ms 缓冲耗时: 320.45ms
实际应用场景[编辑 | 编辑源代码]
场景1:大文件逐行处理[编辑 | 编辑源代码]
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
new BufferedInputStream(
new FileInputStream("huge_log.txt"))))) {
br.lines().forEach(line -> {
// 处理每行日志
if(line.contains("ERROR")) {
System.out.println("发现错误: " + line);
}
});
}
场景2:网络资源下载[编辑 | 编辑源代码]
URL url = new URL("https://example.com/large.zip");
try (BufferedInputStream in = new BufferedInputStream(url.openStream());
FileOutputStream out = new FileOutputStream("local_copy.zip")) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
}
}
高级技巧[编辑 | 编辑源代码]
缓冲区大小优化[编辑 | 编辑源代码]
缓冲区大小应考虑:
- 文件平均大小(小文件适合较小缓冲区)
- 可用内存(通常8KB-64KB为宜)
- 存储介质特性(SSD可适当减小缓冲区)
与NIO结合使用[编辑 | 编辑源代码]
Java NIO的`ByteBuffer`可进一步提升性能:
try (FileChannel channel = FileChannel.open(Paths.get("data.bin"))) {
ByteBuffer buffer = ByteBuffer.allocateDirect(8192); // 直接缓冲区
while (channel.read(buffer) != -1) {
buffer.flip();
// 处理数据...
buffer.clear();
}
}
常见问题[编辑 | 编辑源代码]
Q: 为什么读取完数据后需要关闭流?
A: 关闭流会释放系统资源(如文件句柄),且会强制刷新缓冲区。使用try-with-resources可自动处理。
Q: 缓冲区大小是否越大越好?
A: 过大的缓冲区会导致:①内存浪费 ②延迟首次数据可用时间 ③可能触发GC
Q: 如何复用缓冲区?
A: 可创建全局缓冲区池(高级用法):
class BufferPool {
private static final ConcurrentLinkedQueue<byte[]> pool = new ConcurrentLinkedQueue<>();
static byte[] getBuffer(int size) {
byte[] buf = pool.poll();
return buf != null && buf.length >= size ? buf : new byte[size];
}
static void returnBuffer(byte[] buf) {
if(buf != null) pool.offer(buf);
}
}
最佳实践[编辑 | 编辑源代码]
1. 始终使用try-with-resources确保流关闭 2. 对敏感数据读取后清空缓冲区:
Arrays.fill(buffer, (byte)0); // 清除内存中的敏感数据
3. 考虑使用`BufferedInputStream`包装所有`InputStream`实例(除非确定不需要缓冲)
页面模块:Message box/ambox.css没有内容。
多线程环境下,`BufferedInputStream`实例不是线程安全的!需要外部同步或使用独立实例。 |