FileInputStream 的 read() 方法返回 -1 表示已读到文件末尾,属正常行为;需用 while((b=fis.read())!=-1) 正确判断,不可误判为错误。

FileInputStream 读取文件时为什么返回 -1?
因为已经读到文件末尾,read() 方法返回 -1 是正常行为,不是错误。很多人误以为是路径错或权限问题,其实只是循环没控制好。
- 必须用
while ((b = fis.read()) != -1)判断,不能写成!= 0或漏掉括号 - 如果文件为空,第一次
read()就返回-1,循环体一次都不会执行 -
read()每次只读 1 字节,返回int(0–255),不是byte;直接强转可能丢符号位,但这里不影响判断
想一次读完所有字节,该用 read(byte[]) 还是 readAllBytes()?
Java 9+ 推荐用 readAllBytes(),它内部已处理循环读取和扩容,代码简洁且不易出错;老版本只能靠 read(byte[]) 手动循环。
-
fis.readAllBytes()自动分配合适大小的byte[],无需预估文件长度 - 用
read(byte[])时,返回值是「本次实际读到的字节数」,可能小于数组长度,必须用返回值截取有效数据 - 常见错误:把整个
byte[]当作内容输出,导致末尾出现乱码(其实是未填充的 0) - 大文件慎用——
readAllBytes()会一次性加载全部内容进内存
FileInputStream 抛出 FileNotFoundException 怎么快速定位原因?
不是“文件不存在”这么简单,要逐项检查路径解析、工作目录、权限三要素。
- 传入的是相对路径时,JVM 当前工作目录(
System.getProperty("user.dir"))决定根位置,不是类路径也不是 IDE 运行目录 - 路径中含中文或空格,未做 URL 编码或未用
File.toURI()转换,容易被截断 - Linux/macOS 下注意大小写敏感;Windows 上虽然不敏感,但某些安全策略会拦截访问
- IDE 运行时,确认「Working directory」配置是否覆盖了默认路径
关闭流时 try-with-resources 为什么比 finally 更可靠?
因为 close() 本身可能抛异常,手动写 finally 容易掩盖原始异常,而 try-with-resources 保证资源释放且不吞异常。
- 必须把
FileInputStream声明在 try 括号内,如try (FileInputStream fis = new FileInputStream(path)) { ... } - 不要在 try 块里再调用
fis.close(),会导致IllegalStateException - 如果同时操作多个流(比如读 + 写),可以写在同一 try 后括号里,用分号隔开
- 即使构造函数抛出
FileNotFoundException,try-with-resources 仍能确保后续声明的资源不泄漏
真正麻烦的不是读数据,而是路径怎么算对、异常怎么传出来、大文件要不要分块——这些细节不写进日志,线上就只能靠猜。

















