AWS EC2服务器从公共Jar资源获取File对象时遇FileNotFoundException
解决Jar内部资源无法转为File对象的问题
Hey there! Let's break down why this is happening and get it fixed for you.
问题根源
你遇到的核心问题是:Jar包内部的资源并不是文件系统里的独立物理文件。在Eclipse开发环境中,你的key.pem是直接放在项目classpath目录下的真实文件,所以getResource()返回的是file:协议的URI,能顺利转成File对象。但当项目打包成Jar(包括依赖的公共Jar)后,key.pem变成了Jar包内的一个条目,此时getResource()返回的是jar:协议的URI,Paths.get(res.toURI())无法识别这种格式,自然就抛出FileNotFoundException——EC2上运行的是打包后的Jar,所以问题就暴露出来了。
解决方案
根据你的需求,分两种场景处理:
1. 必须使用File对象(比如某些API强制要求)
如果业务代码一定要用File对象,可以把Jar里的资源复制到临时文件中,再使用这个临时文件:
try { // 获取资源的输入流 InputStream inputStream = ResidentHelperService.class.getClassLoader().getResourceAsStream("key.pem"); if (inputStream == null) { throw new RuntimeException("资源文件key.pem不存在"); } // 创建临时文件,保留.pem后缀 File tempFile = File.createTempFile("temp-key", ".pem"); // 程序正常退出时自动删除临时文件 tempFile.deleteOnExit(); // 将输入流内容复制到临时文件 Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING); // 现在tempFile就是可用的File对象了 System.out.println("临时文件路径:" + tempFile.getAbsolutePath()); } catch (IOException e) { e.printStackTrace(); }
2. 可以改用InputStream(推荐)
如果你的业务代码能接受InputStream(大多数处理文件的API都支持),直接用getResourceAsStream()获取输入流是最简单高效的方式,完全避开File对象的限制:
InputStream pemStream = ResidentHelperService.class.getClassLoader().getResourceAsStream("key.pem"); if (pemStream == null) { throw new RuntimeException("资源文件key.pem不存在"); } // 直接用pemStream进行后续操作,比如读取密钥内容等
额外提示
- 可以解压依赖的
project-common-utilityJar包,确认key.pem确实被打包到了BOOT-INF/lib/project-common-utility-0.0.1-SNAPSHOT.jar!/key.pem路径下,避免资源漏打包的情况。 - 临时文件方案虽然能解决File对象的需求,但会产生临时文件,
deleteOnExit()能保证JVM正常退出时清理,若程序异常退出可能会残留文件,必要时可以手动添加清理逻辑。
内容的提问来源于stack exchange,提问作者Supriya Shelar
相关产品推荐
相关产品推荐

