根本原因是退回字节数超过缓冲区容量,PushbackInputStream默认仅1字节,需显式指定足够size(如new PushbackInputStream(in, 16)),且unread操作受剩余空间限制,多次unread未read会导致缓冲区满。

当调用 unread() 时抛出 IOException: Push back buffer is full,根本原因是尝试退回的字节数超过了构造时指定的缓冲区容量。这不是流已关闭或底层异常,而是缓冲区硬性限制触发的失败。
确认构造时设置的缓冲区大小
PushbackInputStream 默认缓冲区仅 1 字节。如果代码中使用的是无参构造器:new PushbackInputStream(in),那就只能安全 unread(1) 一次。任何多字节回退(如 unread(new byte[]{0x01, 0x02}))必然失败。
- 检查实例化位置,确认是否显式传入了足够大的
size参数 - 例如协议头最多需回退 8 字节(魔数 4 + 版本 2 + 校验 2),应写成:
new PushbackInputStream(in, 16)(留余量更稳妥) - 避免复用同一实例处理差异巨大的协议——缓冲区大小难兼顾
核对 unread 调用的实际字节数
unread() 有三个重载,但都受限于缓冲区剩余空间:
-
unread(int b):退回 1 字节 -
unread(byte[] b):退回整个数组长度(b.length) -
unread(byte[] b, int off, int len):退回len字节
常见误判:以为 unread(new byte[10]) 只推回有效内容,实际是推回全部 10 字节。若缓冲区只剩 3 字节空位,就会报错。
立即学习“Java免费学习笔记(深入)”;
排查“多次 unread”导致缓冲区填满
缓冲区是先进后出(LIFO)结构,但容量固定。连续调用 unread() 而未执行 read() 消费,会快速占满:
- 例如
buf大小为 4,执行unread(0x01)、unread(0x02)、unread(0x03)、unread(0x04)后缓冲区已满 - 此时再调用任意
unread(...)都会触发异常 - 注意:
read()每次只取一个字节,必须调用足够多次才能清空缓冲区
检查是否在 close() 前遗漏 read 操作
虽然这不直接导致 full 报错,但容易引发连锁问题:
- 如果
unread()后未读就close(),缓冲区字节永久丢失,后续逻辑可能因数据缺失而反复尝试回退 - 尤其在解析循环中:某次
unread()后异常退出,未清理缓冲区,下次重建实例前状态已不可控 - 建议在关键路径加日志,记录
unread字节数与available()返回值对比


















