Java应用部署CAE容器后写入文件遇FileNotFoundException
解决CAE容器中Java应用写入配置文件的FileNotFoundException问题
问题根源
本地开发时,src/main/resources是文件系统中的实际目录,因此可以直接写入;但部署到CAE容器后:
- 应用通常被打包为JAR/WAR包,
src/main/resources下的文件会被嵌入到包内,无法直接写入。 - 容器的应用部署目录通常是只读的,即使路径存在也没有写入权限,导致
FileNotFoundException。
而getResourceAsStream能正常读取,是因为它读取的是类路径中的资源(不管资源在JAR内还是文件系统中),但该方法仅支持读取操作。
解决方案
1. 使用容器允许的可写外部目录
容器环境通常会提供可写的目录,比如临时目录/tmp(注意:临时目录的内容会在容器重启后丢失),或者CAE平台提供的持久化存储目录(如果有)。
示例代码(使用临时目录):
// 获取JVM临时目录 String tempDir = System.getProperty("java.io.tmpdir"); File configFile = new File(tempDir, "config.ini"); // 初始化:如果文件不存在,从类路径复制初始配置 if (!configFile.exists()) { try { configFile.createNewFile(); // 从类路径读取初始配置并写入到可写文件 try (InputStream classpathIs = PropertiesUtil.class.getResourceAsStream("/config.ini"); OutputStream fileOs = new FileOutputStream(configFile)) { byte[] buffer = new byte[1024]; int readLen; while ((readLen = classpathIs.read(buffer)) != -1) { fileOs.write(buffer, 0, readLen); } } } catch (IOException e) { e.printStackTrace(); } } // 写入更新后的secretId Wini ini = new Wini(configFile); ini.put("id", currentId); ini.store(); // 必须调用store方法保存修改
如果CAE平台提供持久化存储卷,可通过环境变量或启动参数指定该目录路径,替换上述代码中的tempDir即可。
2. 应用启动时创建自定义可写目录
你可以在应用启动时创建自定义目录,但需要确保该目录在CAE容器中拥有写入权限:
- 在容器部署配置中,配置挂载一个可写的存储卷到指定路径(比如
/app/config)。 - 在应用启动参数中添加系统属性,比如
-Dconfig.dir=/app/config。 - 代码中读取该系统属性并创建目录(如果不存在):
// 读取自定义配置目录,默认使用临时目录 String configDir = System.getProperty("config.dir", System.getProperty("java.io.tmpdir")); File dir = new File(configDir); // 确保目录存在 if (!dir.exists()) { dir.mkdirs(); } File configFile = new File(dir, "config.ini"); // 后续初始化、写入逻辑同方案1
3. 替代方案:使用配置中心/分布式缓存
容器化环境中,文件存储并不是最可靠的方案,推荐使用CAE平台提供的配置中心(比如Nacos、Apollo)或分布式缓存(比如Redis)来存储secretId:
- 应用启动时从配置中心/缓存读取最新的secretId。
- 轮换secretId时,直接写入配置中心/缓存。
- 这种方式无需依赖文件系统,且能保证重启后获取到最新值,更适合云原生环境。
总结
- 永远不要尝试写入类路径下的资源文件,容器化环境中这类资源要么不可写,要么路径不存在。
- 优先使用平台提供的持久化可写目录或配置中心,避免临时目录带来的数据丢失问题。
内容的提问来源于stack exchange,提问作者World of Titans
相关产品推荐
相关产品推荐

