从可运行Jar读取资源:Eclipse正常但Java命令行报错排查
问题
尝试从可运行Jar中读取目录内的文件,以下代码在Eclipse中可正常运行,但使用Java命令行运行Jar时无法工作。
代码示例
import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; public class mmm { public static void main(String[] args) throws IOException, URISyntaxException { mmm mmm1 = new mmm(); ClassLoader classLoader = mmm1.getClass().getClassLoader(); String locationPattern = "classpath*:/cc/ff/rr/tttt**"; // tttt是包含nn.txt、ss.txt两个文件的资源文件夹 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource[] resources = resolver.getResources(locationPattern); System.out.println("Number of files " + resources.length); for (Resource resource : resources) { System.out.println("file :" + resource.getFilename()); } } }
命令行运行错误信息
java.io.FileNotFoundException: URL [rsrc:cc/ff/rr/] cannot be resolved to absolute file path because it does not reside in the file system: rsrc:cc/ff/rr/ at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:204) at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52) at org.springframework.core.io.UrlResource.getFile(UrlResource.java:168) at org.springframework.core.io.support.PathMatchingResourcePatternResolver.doFindPathMatchingFileResources(PathMatchingResourcePatternResolver.java:528) at org.springframework.core.io.support.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:349) at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:267) at cc.ff.rr.mmm.main(mmm.java:36) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) at java.base/java.lang.reflect.Method.invoke(Method.java:578) at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:61)
问题原因与解决方案
核心问题
- 资源存储形式差异:Eclipse中资源是文件系统里的独立文件,Spring可以通过文件路径直接访问;但打包成Jar后,资源嵌入在Jar内部,不是文件系统中的真实文件,此时Spring内部调用的
getFile()方法必然失败。 - 路径匹配格式错误:
classpath*:/cc/ff/rr/tttt**的写法不规范,正确的递归匹配子目录和文件需要写成classpath*:/cc/ff/rr/tttt/**,缺少斜杠会导致匹配逻辑出错。 - Jar-in-Jar加载器的特殊协议:错误栈显示用了Eclipse的Jar-in-Jar打包,这种方式用
rsrc:协议加载资源,而Spring的PathMatchingResourcePatternResolver对该协议支持不足,无法正确解析资源路径。
解决办法
1. 修正资源匹配路径
将路径模式改为标准递归格式,确保能正确匹配目标目录下的所有资源:
String locationPattern = "classpath*:/cc/ff/rr/tttt/**";
2. 改用流方式读取资源
不要依赖getFile()方法访问资源,改用输入流读取内容,适配Jar内资源的访问逻辑:
for (Resource resource : resources) { System.out.println("file :" + resource.getFilename()); // 通过输入流读取资源内容,避免文件系统路径依赖 try (InputStream is = resource.getInputStream()) { // 这里编写资源内容处理逻辑 } }
3. 更换标准打包方式
放弃Eclipse的Jar-in-Jar打包,改用Maven或Gradle的标准打包流程:
- Maven:配置
maven-jar-plugin指定主类,用maven-dependency-plugin管理依赖,打包成标准可执行Jar或带依赖目录的Jar。 - Gradle:通过
jar任务配置主类,使用shadowJar插件打包成Fat Jar。
标准打包会用jar:协议加载资源,Spring能正常处理。
4. 适配Jar-in-Jar的资源读取(可选)
如果必须保留Jar-in-Jar打包,直接通过类加载器枚举资源,绕过Spring的资源解析限制:
ClassLoader classLoader = mmm1.getClass().getClassLoader(); Enumeration<URL> urls = classLoader.getResources("cc/ff/rr/tttt/"); while (urls.hasMoreElements()) { URL url = urls.nextElement(); // 根据URL类型解析资源,比如处理Jar内的条目 }
内容的提问来源于stack exchange,提问作者ibrahim
相关产品推荐
相关产品推荐

