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

可执行Java Jar无法读取资源路径,加载MP3文件失败求助

问题描述

在VS Code中运行Java应用时,读取/sounds/music/MainThemes目录下的MP3文件一切正常,但生成Jar包执行后,无法正常加载文件。通过日志打印发现,代码执行到--- 2 ---后无法进入while循环,BufferedReader读取流直接返回null,导致mainThemeMediaList列表未被填充。

需求是读取/sounds/music/MainThemes下所有.mp3文件并添加到列表中,相关代码如下:

private void loadMainThemes() throws AudioLoadingException {
    try {
        System.out.println("--- 1 ---");
        InputStream inputStream = getClass().getResourceAsStream("/sounds/music/MainThemes");
        System.out.println(inputStream);
        if (inputStream != null) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            System.out.println(reader);
            String line;
            System.out.println("--- 2 ---");
            while ((line = reader.readLine()) != null) {
                System.out.println("--- 3 ---");
                if (line.endsWith(".mp3")) {
                    System.out.println("--- 4 ---");
                    Media media = new Media(getClass().getResource("/sounds/music/MainThemes/" + line).toString());
                    System.out.println("--- 5 ---");
                    mainThemeMediaList.add(media);
                }
            }
        } else {
            throw new AudioLoadingException("MainThemes resource not found.");
        }
    } catch (IOException e) {
        throw new AudioLoadingException("Failed to load MainThemes. " + e.getMessage());
    }
}
问题原因

IDE环境中,/sounds/music/MainThemes是文件系统中的真实目录,getResourceAsStream会返回该目录的列表流,BufferedReader可以读取到目录下的文件名。但打包成Jar后,资源是压缩包内的条目,无法通过读取目录流的方式获取内部文件列表——此时inputStream虽不为null,但读取到的内容并非文件名列表,直接返回null,导致循环无法执行。

解决方案

方法1:纯Java通用方案(兼容IDE与Jar环境)

该方法自动识别运行环境,分别处理文件系统(IDE)和Jar包两种情况:

private void loadMainThemes() throws AudioLoadingException {
    try {
        String basePath = "/sounds/music/MainThemes";
        URL resourceUrl = getClass().getResource(basePath);
        if (resourceUrl == null) {
            throw new AudioLoadingException("MainThemes resource not found.");
        }

        if ("file".equals(resourceUrl.getProtocol())) {
            // IDE环境:直接遍历文件系统目录
            File dir = new File(resourceUrl.toURI());
            File[] mp3Files = dir.listFiles((file) -> file.getName().endsWith(".mp3"));
            if (mp3Files != null) {
                for (File file : mp3Files) {
                    Media media = new Media(getClass().getResource(basePath + "/" + file.getName()).toString());
                    mainThemeMediaList.add(media);
                }
            }
        } else if ("jar".equals(resourceUrl.getProtocol())) {
            // Jar环境:解析Jar包内的资源条目
            String jarPath = resourceUrl.getPath().substring(5, resourceUrl.getPath().indexOf("!"));
            JarFile jarFile = new JarFile(jarPath);
            Enumeration<JarEntry> entries = jarFile.entries();
            String targetDir = basePath.substring(1) + "/"; // 去掉开头的/,拼接目录后缀

            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                String entryName = entry.getName();
                // 筛选目标目录下的MP3文件,排除目录本身
                if (entryName.startsWith(targetDir) && entryName.endsWith(".mp3") && !entry.isDirectory()) {
                    String fileName = entryName.substring(targetDir.length());
                    Media media = new Media(getClass().getResource(basePath + "/" + fileName).toString());
                    mainThemeMediaList.add(media);
                }
            }
            jarFile.close();
        }
    } catch (URISyntaxException | IOException e) {
        throw new AudioLoadingException("Failed to load MainThemes. " + e.getMessage());
    }
}

方法2:Jar环境专属方案

如果确定应用仅以Jar包形式运行,可以直接枚举Jar内的资源条目:

private void loadMainThemes() throws AudioLoadingException {
    try {
        // 获取当前Jar文件路径
        String jarPath = getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
        JarFile jarFile = new JarFile(jarPath);
        Enumeration<JarEntry> entries = jarFile.entries();
        
        String targetDir = "sounds/music/MainThemes/";
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String entryName = entry.getName();
            if (entryName.startsWith(targetDir) && entryName.endsWith(".mp3") && !entry.isDirectory()) {
                Media media = new Media(getClass().getResource("/" + entryName).toString());
                mainThemeMediaList.add(media);
            }
        }
        jarFile.close();
    } catch (URISyntaxException | IOException e) {
        throw new AudioLoadingException("Failed to load MainThemes. " + e.getMessage());
    }
}

方法3:Spring环境下的简化方案

如果项目依赖Spring框架,可以用PathMatchingResourcePatternResolver快速扫描资源,自动兼容两种环境:

private void loadMainThemes() throws AudioLoadingException {
    try {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 匹配目标目录下所有MP3文件
        Resource[] resources = resolver.getResources("classpath:/sounds/music/MainThemes/*.mp3");
        
        for (Resource resource : resources) {
            Media media = new Media(resource.getURL().toString());
            mainThemeMediaList.add(media);
        }
    } catch (IOException e) {
        throw new AudioLoadingException("Failed to load MainThemes. " + e.getMessage());
    }
}

内容的提问来源于stack exchange,提问作者Shodan4004

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:23:19