相同路径读取文件正常,写入时抛出FileNotFoundException问题求助
问题分析与解决方案
嘿,我来帮你搞定这个读写路径不一致的问题!
首先得明确核心原因:你用getClassLoader().getResourceAsStream()能成功读取文件,但写入时报FileNotFoundException,本质是类加载器的资源路径和文件系统的实际路径不是一回事!
为什么会这样?
getResourceAsStream()是从类路径(比如IDE里编译后的classes目录、打包后的jar包内部)加载资源的,而你写入时直接用相同的filePath,JVM会把它当成当前工作目录下的相对路径——这两个位置大概率完全不同,自然找不到文件。
看你给出的ConfigHandler代码,filePath = "./com.triemond.communicate.config/config.cfg":
- 读取时,类加载器会在类路径里找这个层级的文件;
- 写入时,JVM会去程序运行的当前目录(比如项目根目录)下找
./com.triemond.communicate.config/config.cfg,这个目录可能根本不存在,或者文件压根不在那。
具体解决方案
1. 先获取资源的实际文件系统路径(开发环境适用)
如果是在IDE里开发,你可以先拿到资源的真实文件路径,再用这个路径写入:
// 在ConfigHandler里添加获取真实路径的逻辑 URL resourceUrl = this.getClass().getClassLoader().getResource(filePath); if (resourceUrl != null) { try { File actualConfigFile = new File(resourceUrl.toURI()); String realFilePath = actualConfigFile.getAbsolutePath(); // 后续写入就用realFilePath } catch (URISyntaxException e) { e.printStackTrace(); } }
2. 完善写入逻辑(确保目录存在)
不管用哪种路径,写入前一定要确保父目录存在,否则也会报找不到文件的异常:
public void saveConfig() throws IOException { URL resourceUrl = this.getClass().getClassLoader().getResource(filePath); if (resourceUrl == null) { throw new FileNotFoundException("配置文件在类路径中不存在:" + filePath); } File configFile = new File(resourceUrl.toURI()); // 确保父目录存在,不存在就创建 configFile.getParentFile().mkdirs(); // 写入配置 try (OutputStream outputStream = new FileOutputStream(configFile)) { this.configFile.store(outputStream, "更新配置"); } }
3. 生产环境/ jar包环境的处理(重点)
如果你的程序要打包成jar包,上面的方法就失效了——因为jar包内部的资源不是文件系统里的真实文件,无法直接写入。这时候建议把配置文件放到jar包外部的独立目录,比如:
// 修改ConfigHandler的路径逻辑,优先读取系统参数指定的路径 private String filePath = System.getProperty("config.path", "./config/config.cfg"); public ConfigHandler(Communicator communicator) { configFile = new Properties(); File configFile = new File(filePath); try { if (configFile.exists()) { // 读取已有配置 try (InputStream stream = new FileInputStream(configFile)) { this.configFile.load(stream); } } else { // 不存在则创建目录和默认配置 configFile.getParentFile().mkdirs(); configFile.createNewFile(); // 设置默认配置项 this.configFile.setProperty("example.key", "default.value"); saveConfig(); } } catch(Exception e) { e.printStackTrace(); } } // 写入方法直接用外部路径 public void saveConfig() throws IOException { try (OutputStream outputStream = new FileOutputStream(filePath)) { this.configFile.store(outputStream, "Updated config"); } }
运行jar包时,可以通过参数指定配置路径:
java -jar your-app.jar -Dconfig.path=/opt/your-app/config/config.cfg
总结
核心就是区分类路径资源和文件系统路径:读取可以用类加载器,但写入必须对应到文件系统的真实位置。根据你的运行环境(开发/生产、本地/ jar包)选择对应的路径处理方式就好啦!
内容的提问来源于stack exchange,提问作者BRHSM
相关产品推荐
相关产品推荐

