You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从可运行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)
问题原因与解决方案

核心问题

  1. 资源存储形式差异:Eclipse中资源是文件系统里的独立文件,Spring可以通过文件路径直接访问;但打包成Jar后,资源嵌入在Jar内部,不是文件系统中的真实文件,此时Spring内部调用的getFile()方法必然失败。
  2. 路径匹配格式错误:classpath*:/cc/ff/rr/tttt**的写法不规范,正确的递归匹配子目录和文件需要写成classpath*:/cc/ff/rr/tttt/**,缺少斜杠会导致匹配逻辑出错。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:17:49