FileInputStream抛FileNotFoundException主因是路径错误或文件不存在,且相对路径基于JVM启动目录;FileOutputStream默认覆盖,追加需设append为true;应使用缓冲流提升性能;关闭流需判空或用try-with-resources。

FileInputStream 读取文件时为什么总抛出 FileNotFoundException
常见原因是路径写错或文件不存在,但更隐蔽的问题是:相对路径基于 JVM 启动目录而非源码所在目录。比如在 IDE 中运行时,当前工作目录通常是项目根目录,不是 src 或 resources 目录。
- 用
new FileInputStream("data.bin")前,先确认该文件是否真在当前工作目录下(可打印System.getProperty("user.dir")查看) - 推荐用绝对路径或类路径定位资源:
getClass().getResource("/data.bin")返回URL,再用url.toURI()构造File - 别忽略
FileNotFoundException是IOException的子类,必须捕获或声明抛出
FileOutputStream 写入时覆盖还是追加?如何控制
FileOutputStream 默认覆盖目标文件;要追加必须显式启用 append 模式,靠构造函数第二个 boolean 参数控制。
- 覆盖写入:
new FileOutputStream("log.txt") - 追加写入:
new FileOutputStream("log.txt", true) - 如果目标文件不存在,两种方式都会自动创建;但父目录不存在会直接抛
FileNotFoundException(不会自动建目录) - 写入后务必调用
flush()和close(),否则缓冲区内容可能未落盘
字节流读写效率低?要不要加 BufferedInputStream/BufferedOutputStream
直接用 FileInputStream / FileOutputStream 每次只读写一个字节或小数组,系统调用频繁,性能差。加缓冲层是标准做法。
- 包装方式:
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("in.bin")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("out.bin"))) { int b; while ((b = bis.read()) != -1) { bos.write(b); } } - 默认缓冲区大小是 8192 字节,够用;如需调整,可用带
int size参数的构造函数 - 注意:
BufferedOutputStream的write(int)方法仍会触发内部缓冲,但频繁单字节写仍慢;批量写(如write(byte[], int, int))更高效
关闭流时出现 NullPointerException 怎么办
典型写法错误:把流声明在 try 块内,导致 finally 里无法访问;或流初始化失败(如文件不可读),变量仍为 null,却在 finally 中无条件调用 close()。
立即学习“Java免费学习笔记(深入)”;
- 正确做法是声明在 try 外并初始化为
null,关闭前判空:FileInputStream fis = null; try { fis = new FileInputStream("a.txt"); // ... } finally { if (fis != null) { try { fis.close(); } catch (IOException e) { /* 忽略或记录 */ } } } - 更简洁的方式是使用 try-with-resources(Java 7+),它自动处理 null 安全和异常抑制:
try (FileInputStream fis = new FileInputStream("a.txt"); FileOutputStream fos = new FileOutputStream("b.txt")) { // 自动 close,即使构造函数抛异常也安全 } - 注意:try-with-resources 要求资源实现
AutoCloseable,FileInputStream和FileOutputStream都满足
实际用字节流做文件拷贝时,最容易被忽略的是异常处理粒度——不能只在外层 catch 一个 IOException 就完事,要区分是读失败、写失败还是关闭失败;而 try-with-resources 能帮你挡住大部分底层细节,但得清楚它不捕获业务逻辑异常。










