Java的IO流和IO流的Buffer包装类
Java IO流概述
Java IO流是用于处理输入输出操作的API,主要分为字节流和字符流两大类。字节流以字节为单位操作数据,适合处理二进制文件;字符流以字符为单位操作数据,适合处理文本文件。
字节流(Byte Streams)
字节流的核心类是InputStream
和OutputStream
,它们是抽象类,提供了基本的读写方法。
常用字节流类:
FileInputStream
/FileOutputStream
:用于文件读写。BufferedInputStream
/BufferedOutputStream
:带缓冲区的流,提高性能。DataInputStream
/DataOutputStream
:用于读写基本数据类型。
字符流(Character Streams)
字符流的核心类是Reader
和Writer
,它们是抽象类,提供了字符读写方法。
常用字符流类:
FileReader
/FileWriter
:用于文件读写。BufferedReader
/BufferedWriter
:带缓冲区的流,提高性能。
InputStreamReader
/OutputStreamWriter
:字节流与字符流的桥梁。
NIO(New IO)
Java NIO提供了更高效的IO操作,基于通道(Channel)和缓冲区(Buffer)实现。
核心组件:
Buffer
:数据容器。Channel
:数据传输通道。Selector
:多路复用器。
BufferInputStream的原理
BufferedInputStream 的基本概念
BufferedInputStream 是 Java 中用于缓冲输入流的装饰器类,继承自 FilterInputStream
。它通过内部缓冲区减少对底层输入流的直接读取次数,从而提高读取效率。
内部缓冲区机制
BufferedInputStream 内部维护一个字节数组作为缓冲区,默认大小为 8192 字节(8KB)。缓冲区在首次读取时填充,后续读取操作优先从缓冲区获取数据,减少底层 I/O 操作。
protected volatile byte buf[];
关键字段说明
buf[]
:缓冲区数组,存储从底层流读取的数据。count
:缓冲区中有效数据的结束位置。pos
:当前读取位置指针。markpos
:标记位置(用于mark/reset
操作)。marklimit
:标记后允许读取的最大字节数。
读取数据的流程
当调用 read()
方法时,BufferedInputStream 会检查缓冲区是否有剩余数据。若无数据或缓冲区已耗尽,会触发 fill()
方法从底层流重新填充缓冲区。
public synchronized int read() throws IOException {if (pos >= count) {fill();if (pos >= count) return -1;}return buf[pos++] & 0xff;
}
fill() 方法的作用
fill()
方法负责重新填充缓冲区:
- 若缓冲区未初始化,分配默认或指定大小的缓冲区。
- 清除无效数据(如
markpos
为 -1 时直接重置缓冲区)。 - 从底层流读取数据到缓冲区,更新
pos
和count
。
标记与重置功能
BufferedInputStream 支持 mark(int readlimit)
和 reset()
:
mark(int readlimit)
:记录当前位置到markpos
,并设置marklimit
。reset()
:将pos
恢复到markpos
的位置,实现重复读取。
public synchronized void mark(int readlimit) {marklimit = readlimit;markpos = pos;
}
性能优化点
- 减少磁盘 I/O:通过缓冲区批量读取数据,减少直接访问底层流的次数。
- 缓冲区大小调优:可根据实际场景调整缓冲区大小(通过构造函数指定),平衡内存与 I/O 性能。
适用场景
- 频繁读取小量数据时(如逐字节读取)。
- 需要基于
mark/reset
实现回溯操作的场景。 - 底层流为高延迟 I/O(如网络流或文件流)。
注意事项
- 线程安全:
BufferedInputStream
的方法使用synchronized
修饰,但多线程共享时仍需注意状态一致性。 - 资源释放:关闭
BufferedInputStream
会自动关闭其包装的底层流。 - 缓冲区一致性:直接操作底层流可能导致缓冲区数据不一致(如跳过字节时需调用
BufferedInputStream.skip()
)。