InputStream读取常阻塞或读不到数据,根本原因是未检查read()返回值;返回-1表示流结束,0表示暂无数据,盲目循环致CPU空转;批量读需用返回值控制写入长度,网络流须设超时,文件流推荐Files.newInputStream()。

InputStream 读取字节时为什么经常阻塞或读不到数据?
根本原因通常是调用 read() 方法后没检查返回值,或误以为每次都能读满缓冲区。该方法返回实际读到的字节数,-1 表示流已结束;返回 0 不代表结束,而是本次无数据可读(比如网络流暂无新包),盲目循环会导致 CPU 空转。
- 始终用
int b = in.read()判断,而非in.read() != -1在 while 条件里重复调用(会跳过第一个字节) - 批量读取优先用
read(byte[] b),但必须用返回值控制写入长度:int len = in.read(buf); out.write(buf, 0, len); - 网络或管道类流需配合超时设置(如
Socket.setSoTimeout()),否则可能无限等待 - 文件类流建议用
Files.newInputStream()替代裸FileInputStream,自动处理路径和异常
OutputStream 写入后文件为空或内容不全?
最常见原因是忘了调用 flush() 或 close()。缓冲区未刷新时,数据还卡在内存里,进程退出前若未显式刷出,就直接丢失。
-
write()只是把数据塞进缓冲区,不保证落盘;flush()强制清空缓冲区,close()会隐式调用flush(),但依赖try-with-resources更安全 - 避免手动
close():用try (OutputStream out = new FileOutputStream("a.txt")) { ... },即使异常也能释放资源 - 追加写入要传
true给FileOutputStream构造函数:new FileOutputStream("log.txt", true) - 小量数据(如单个 byte)直接用
write(int b)即可,别硬套 byte[] 缓冲区
InputStream 和 OutputStream 能否直接转换成 String?
不能直接强转,必须经过编码解码。字节流本身无字符概念,String 是 Unicode 字符序列,中间必须指定字符集,否则默认平台编码(Windows 是 GBK,Linux/macOS 通常是 UTF-8),极易乱码。
- 读取为字符串:用
new String(bytes, StandardCharsets.UTF_8),别用new String(bytes) - 更稳妥方式是包装成字符流:
new InputStreamReader(in, StandardCharsets.UTF_8),再用BufferedReader逐行读 - 写入字符串:用
OutputStreamWriter包装,out.write(str)自动按指定编码转字节 - 如果原始字节本就是文本且确定编码,可用
Files.readString(path, UTF_8)/Files.writeString(path, str, UTF_8)(Java 11+)
复制文件时用 byte[] 缓冲区多大才合适?
64KB(new byte[8192] 或 new byte[65536])是通用折中值。太小(如 1B)导致系统调用频繁、性能差;太大(如 1MB)浪费堆内存,且对多数 I/O 场景提升有限。
立即学习“Java免费学习笔记(深入)”;
- 磁盘文件复制:8KB–64KB 均可,JDK 自带的
Files.copy()内部用的就是 8192 - 网络传输:可略小(4KB),降低单次延迟敏感度
- 嵌入式或内存受限环境:可降到 1KB,但需接受性能折损
- 注意:不要用
available()预估长度——它只反映“当前可非阻塞读取的字节数”,对文件流可能返回全长,对网络流常返回 0
OutputStream 的写入逻辑,都要确认是否已 flush() 或由 try-with-resources 保障关闭。这两点出错,现象往往是“程序没报错,但结果不对”。










