PushbackInputStream 是 Java IO 中支持字节回退的过滤流,通过内部缓冲区实现预读判断与推回,仅能回退不超过缓冲区容量的字节数,且需 read 后才能再次 unread。

PushbackInputStream 是 Java IO 中一个特殊的过滤流,它允许你将已读取的字节“推回”(即回退)到输入流中,供后续再次读取。它常用于需要“预读 + 判断 + 回退”的场景,比如词法分析、协议解析或自定义格式解析。
核心原理:内部缓冲区实现回退
PushbackInputStream 内部维护一个固定大小的字节数组缓冲区(默认 1 字节,可指定更大容量)。当你调用 unread(int b) 或 unread(byte[] b) 时,数据不是真正写回原始流,而是暂存到这个缓冲区中;后续 read() 会优先从缓冲区取,缓冲区空了才继续从底层流读。
注意:不能无限制回退 —— 只能回退不超过缓冲区容量的字节数,且多次 unread 必须在未 read 的前提下进行(否则抛 IOException)。
基本使用步骤
- 用目标 InputStream(如 FileInputStream、ByteArrayInputStream)构造 PushbackInputStream,并指定回退缓冲区大小(推荐至少 2–4 字节,视协议需求而定)
- 正常调用 read() 获取字节
- 若发现当前字节不符合预期(比如不是数字开头、不是某个关键字首字符),立即调用 unread(b) 把它推回去
- 后续逻辑可重新读取该字节,或切换解析分支
典型示例:跳过空白后读取首个非空白字符
下面代码用 PushbackInputStream 实现“读取下一个非空白字符”,并保证该字符仍留在流中供后续使用:
立即学习“Java免费学习笔记(深入)”;
PushbackInputStream pbis = new PushbackInputStream(in, 1);
int ch;
while ((ch = pbis.read()) != -1) {
if (!Character.isWhitespace((char) ch)) {
pbis.unread(ch); // 推回,留给后续处理
break;
}
}
// 此时流位置已回到第一个非空白字符处,下次 read() 就能拿到它
常见陷阱与注意事项
- 缓冲区溢出:unread 超出构造时指定的长度会抛异常。建议根据最大可能回退字节数设 buffer size(例如解析最多 4 字节的 magic number,就设为 4)
- unread 后不可再 unread:必须至少一次 read 后才能再次 unread,否则报 “push back buffer is full”
- 不支持 mark/reset:它不是通过 mark 实现回退,和 BufferedInputStream 的 mark 不同,不要混用
- 异常处理要谨慎:unread 可能抛 IOException,需捕获并合理处理(比如日志记录 + 关闭流)


















