Heroku读取类路径XML文件遇FileNotFoundException,求FileInputStream解决方案
解决Jar包中ClassPath资源无法通过getFile()获取的问题
问题重现
你碰到的错误信息是这样的:
java.io.FileNotFoundException: 类路径资源[xml/ruleSet.xml]无法解析为绝对文件路径,因为它不在文件系统中:jar:file:/app/target/******-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/xml/ruleSet.xml
原来的代码实现:
File ruleSet = new ClassPathResource("xml/ruleSet.xml").getFile(); pmdConfiguration.setReportFormat("text"); pmdConfiguration.setRuleSets(ruleSet.getAbsolutePath());
说白了,问题根源在于:当应用打包成Jar包后,xml/ruleSet.xml是嵌入在Jar内部的资源,并非操作系统文件系统中的真实文件,所以ClassPathResource.getFile()根本拿不到有效的文件对象,自然也就没法获取绝对路径了。
解决方案:用FileInputStream+临时文件搞定
因为setRuleSets方法只认文件路径,我们可以把Jar里的资源流读取出来,写入一个临时文件,再用这个临时文件的路径去调用方法。具体步骤如下:
- 获取ClassPath资源的输入流
- 创建一个临时文件来存放资源内容
- 将输入流的内容复制到临时文件中
- 使用临时文件的路径调用
setRuleSets - (可选)设置临时文件在JVM退出时自动删除,避免残留垃圾文件
完整代码示例:
import org.springframework.core.io.ClassPathResource; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; // 获取ClassPath资源的输入流 ClassPathResource resource = new ClassPathResource("xml/ruleSet.xml"); try (InputStream inputStream = resource.getInputStream()) { // 创建临时文件,后缀设为.xml方便识别 File tempRuleSet = File.createTempFile("ruleSet", ".xml"); // 让临时文件在JVM退出时自动删除 tempRuleSet.deleteOnExit(); // 将输入流内容写入临时文件 try (FileOutputStream outputStream = new FileOutputStream(tempRuleSet)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } } // 现在可以用临时文件的路径调用setRuleSets了 pmdConfiguration.setReportFormat("text"); pmdConfiguration.setRuleSets(tempRuleSet.getAbsolutePath()); } catch (IOException e) { // 处理异常,比如资源读取失败、临时文件创建失败等 e.printStackTrace(); }
额外说明
- 为什么不能直接传InputStream?因为PMD的
Configuration.setRuleSets()方法设计上只接受文件路径(或者规则集的字符串定义),所以必须通过临时文件中转。 - 临时文件会在JVM退出时自动删除,不用担心磁盘残留;如果需要提前清理,也可以在使用完后主动调用
tempRuleSet.delete()。
内容的提问来源于stack exchange,提问作者Nagendra K S
相关产品推荐
相关产品推荐

