pushbackinputstream 是 java 中支持字节回退的装饰器流,通过内部缓冲区实现预读与撤回,适用于词法分析等需 peek 后决策的场景;其缓冲区大小固定,超出容量会抛 ioexception。

PushbackInputStream 是 Java I/O 中用于“回退一个或多个字节”的装饰器流,适用于需要预读(peek)后决定如何解析的场景,比如词法分析、协议解析或自定义格式读取。
核心原理:缓冲区实现“回退”
它内部维护一个固定大小的字节数组缓冲区(默认 1 字节),调用 unread(int b) 或 unread(byte[] b) 时,把字节“压回”缓冲区;后续 read() 会先从缓冲区取,再读底层流。注意:回退容量有限,超出会抛 IOException。
基本用法:单字节回退
最常见场景是“看一眼是不是某个起始字符”,再决定是否跳过或处理:
- 创建时包装原始
InputStream,可指定缓冲区大小(如new PushbackInputStream(in, 2)支持回退最多 2 字节) - 调用
read()获取一个字节 - 若该字节需“撤回”(比如发现不是预期开头),立即调用
unread(b) - 之后的
read()将返回刚才 unread 的字节
实用示例:跳过 BOM(UTF-8 文件头)
UTF-8 文件可能以 0xEF 0xBB 0xBF 开头,读取时应自动跳过:
byte[] bom = {(byte)0xEF, (byte)0xBB, (byte)0xBF};
PushbackInputStream pbis = new PushbackInputStream(in, bom.length);
int b1 = pbis.read();
if (b1 == bom[0]) {
int b2 = pbis.read();
if (b2 == bom[1]) {
int b3 = pbis.read();
if (b3 == bom[2]) {
// 确认是 BOM,直接忽略,不 unread
} else {
// 不是完整 BOM,把 b2 和 b3 压回去
pbis.unread(b3);
pbis.unread(b2);
}
} else {
// 把 b2 压回去
pbis.unread(b2);
}
} else {
// 把 b1 压回去,继续正常读
pbis.unread(b1);
}
// 后续 read() 就从原始流开头(或 BOM 后)开始
注意事项与限制
- 缓冲区大小必须在构造时指定,一旦创建不能扩容;默认 1 字节,多数简单 peek 场景够用
- 多次
unread()会按“后压入、先弹出”顺序(栈语义),但总字节数不能超缓冲区容量 - 不支持标记(mark/reset),和
BufferedInputStream的 mark 机制无关 - 仅适用于字节流,不处理字符编码;若需字符级回退,应配合
InputStreamReader使用其他方式(如自定义 Reader)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











