fileinputstream的available()返回当前缓冲区已就绪、可立即读取的字节数,并非文件总长或剩余字节数;其值受文件状态、jvm实现及并发修改影响,不可靠,应改用file.length()等明确方法获取文件大小。

FileInputStream 的 available() 方法返回的是“当前可立即读取而不阻塞的字节数”,不是文件总长度,也不是剩余未读字节数,更不能用来预估后续能读多少。
available() 的实际行为
对 FileInputStream 而言,available() 底层调用操作系统提供的 available() 或类似接口(如 Unix 的 ioctl(FIONREAD)),反映的是底层输入流缓冲区中**已就绪、可立刻返回**的字节数。对于本地文件:
- 大多数 JVM 实现(如 HotSpot)在 FileInputStream 初始化后,会尝试获取文件总大小,并将该值作为 available() 的返回结果——但这只是实现细节,不保证跨平台或跨版本一致;
- 如果文件被其他进程并发修改(如追加写入),available() 可能返回小于当前文件长度的值;
- 若 FileInputStream 包装了非普通文件(如管道、设备文件、/proc 下的特殊文件),available() 返回值可能为 0 或不可预测。
为什么不能用 available() 判断文件是否读完
available() 不反映“还剩多少没读”,只反映“此刻缓冲区里有多少能马上拿”。例如:
- 你刚 new 出 FileInputStream,调用 available() 得到 1024,不代表文件只有 1024 字节,也不代表下次 read() 一定能读满 1024;
- 你已 read() 了 500 字节,再调 available(),返回值可能仍是 1024(因为底层缓存已预读)、也可能变小(缓存被清空或文件被截断);
- read() 返回 -1 才表示流末尾,这是唯一可靠的 EOF 判定方式。
替代方案:准确获取文件大小
若目标是知道文件总字节数,应绕过 available(),直接使用:
-
file.length()(File 对象); -
Files.size(path)(NIO.2,支持符号链接和异常处理); - 或通过
getChannel().size()(FileInputStream.getChannel() 返回 FileChannel)。
这些方法返回的是文件系统中该文件的当前大小,语义明确、稳定可靠。
常见误用与建议
有人用 int len = in.available(); byte[] buf = new byte[len]; in.read(buf); 来“一次性读完”,这存在风险:
- available() 返回 0 并不意味流已关闭或结束(比如刚打开时缓存未填充);
- 即使返回非零值,read(byte[]) 仍可能实际读取更少字节(如遇到中断、部分数据未就绪);
- 正确做法是循环 read() 直到返回 -1,或用 try-with-resources + NIO 的 Files.readAllBytes() 等封装好的工具方法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











