读取jar内指定文件夹中所有文件信息

这篇博客介绍了在Java中如何处理程序被打成jar包后读取内部文件的问题。开发过程中,通过模板生成文件时常遇到,但直接用new File()方式在jar环境下会失效。解决方案是检查资源协议,如果是jar,则使用特定方法loadFilesInJar()来读取jar内的文件和目录。文章详细展示了修正后的loadFiles()方法和loadFilesInJar()方法的实现,确保在jar包中也能正确遍历和读取文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我们日常开发过程中会经常遇到通过模板生成文件的业务场景,但是模板可能会经常发生改变,所以我们使用以下代码实现对文件的读取:

private static List<String> loadFiles(String basePath, String fileType, List<String> lst) {
        URL resource = FileUitls.class.getClassLoader().getResource(basePath);
        if (resource == null) {
            return lst;
        }
        File file = new File(resource.getFile());
         if (file.isDirectory()) {
             // 如果当前文件是文件夹 那么获取下面所有的文件
             String[] list = file.list();
             for (String s : list) {
                 loadFiles(basePath + "/" + s, fileType, lst);
             }
         } else if (file.isFile()) {
             if (isEmpty(fileType) || basePath.endsWith("." + fileType)) {
                 lst.add(basePath);
             }
         }
        return lst;
    }

但是当我们将写好的程序打成jar包提供给其它程序使用之后会发现,原本开发环境可以正常读取的文件都会消失,导致这个问题的原因是操作系统会将jar看作是一个文件 而不是一个目录结构,那么如果我们再通过new file的形式去读取jar内的肯定会出现问题。正确的姿势如下:

public class FileUitls{
	/** 
	 *读取指定文件夹下的指定类型的文件
	 * @param basePath 基础目录
	 * @param fileType 文件类型
	 * @param lst       存放目录的容器
	 */
	public static List<String> loadFiles(String basePath, String fileType, List<String> lst) {
	   URL resource = FileUitls.class.getClassLoader().getResource(basePath);
	    if (resource == null) {
	        return lst;
	    }
	    if ("jar".equals(resource.getProtocol())) {
	        //jar包读取
	        loadFilesInJar(basePath, fileType, lst);
	    } else {
	        File file = new File(resource.getFile());
	        if (file.isDirectory()) {
	            // 如果当前文件是文件夹 那么获取下面所有的文件
	            String[] list = file.list();
	            for (String s : list) {
	                loadFiles(basePath + "/" + s, fileType, lst);
	            }
	        } else if (file.isFile()) {
	            if (isEmpty(fileType) || basePath.endsWith("." + fileType)) {
	                lst.add(basePath);
	            }
	        }
	    }
	    return lst;
	}
	// 读取jar内的文件夹信息
	public static List<String> loadFilesInJar(String basePath, String fileType, List<String> lst) {
	    try {
	        ClassLoader classLoader = FileUitls.class.getClassLoader();
	        URL url = classLoader.getResource(basePath);
	        String urlStr = url.toString();
	        // 找到!/ 截断之前的字符串
	        String jarPath = urlStr.substring(0, urlStr.indexOf("!/") + 2);
	        URL jarURL = new URL(jarPath);
	        JarURLConnection jarCon = (JarURLConnection) jarURL.openConnection();
	        JarFile jarFile = jarCon.getJarFile();
	        Enumeration<JarEntry> jarEntrys = jarFile.entries();
	        while (jarEntrys.hasMoreElements()) {
	            JarEntry entry = jarEntrys.nextElement();
	            // 简单的判断路径,如果想做到像Spring,Ant-Style格式的路径匹配需要用到正则。
	            String name = entry.getName();
	            if (name.startsWith(basePath) && !name.equals(basePath)) {
	                if (entry.isDirectory()) {
	                    // 文件夹 迭代
	                    loadFilesInJar(name, fileType, lst);
	                } else if (!lst.contains(name)) {
	                    if (isEmpty(fileType) || name.endsWith("." + fileType)) {
	                        lst.add(name);
	                    }
	                }
	            }
	        }
	    } catch (IOException e) {
	        throw new RuntimeException(e);
	    }
	    return lst;
	}
	
	// 读取指定文件信息
	public static String loadFile(String fileName) {
	    URL resource = FileUitls.class.getClassLoader().getResource(fileName);
	    if (resource == null) {
	        return "";
	    }
	    // 如果文件是jar 那么需要用jar的方式读取
	    if ("jar".equals(resource.getProtocol())) {
	        //jar包读取
	        return loadJarFile(fileName);
	    } else {
	        StringBuilder content = new StringBuilder();
	        FileInputStream fr = null;
	        try  {
	            fr =new FileInputStream(resource.getFile());
	            byte[] bytes = new byte[1024];
	            int len = 0;
	            while ((len = fr.read(bytes)) > 0) {
	                content.append(new String(bytes, 0, len, StandardCharsets.UTF_8));
	            }
	        } catch (IOException e) {
	            e.printStackTrace();
	        }finally {
	            closeIO(fr);
	        }
	        return content.toString();
	    }
	}
	
	// 读取jar包内的文件信息
	public static String loadJarFile(String fileName) {
        StringBuilder content = new StringBuilder();
        InputStream fr = FileUitls.class.getClassLoader().getResourceAsStream(fileName);
        try {
            byte[] bytes = new byte[1024];
            int len = 0;
            while ((len = fr.read(bytes)) > 0) {
                content.append(new String(bytes, 0, len, StandardCharsets.UTF_8));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            closeIO(fr);
        }
        return  content.toString();
    }
}
<think>首先,用户的问题是关于Java运行时如何读取同目录下的配置文件,具体是使用`java -jar`运行jar包时,如何读取jar包同目录下的config文件夹中的配置文件。 用户提供的引用包括: - 引用[1]:提到了配置文件加载的顺序,包括jar包外同级目录的config目录。 - 引用[2]:展示了如何使用`-Dspring.config.location`指定配置文件路径。 - 引用[3]:讨论了读取外部配置文件的问题。 - 引用[4]:提供了读取jar包内部和外部配置文件的方法,包括使用`System.getProperty("user.dir")`。 基于这些,我需要构建一个清晰、结构化的回答,帮助用户理解如何实现这个需求。 回答的结构: 1. **介绍问题**:简要解释Java读取外部配置文件的常见方法。 2. **核心方法**:详细说明如何通过Spring Boot标准Java方式读取配置文件。 3. **具体步骤**:提供代码示例命令行示例。 4. **注意事项**:提到一些常见问题和解决方案。 5. **生成相关问题**:根据内容生成2-3个相关问题。 系统指令要求: - 所有行内数学表达式使用`$...$`格式(但这里可能不涉及数学,所以可能不需要)。 - 独立公式使用`$$...$$`(同样,可能不适用)。 - LaTeX语法正确(但回答主要是文本和代码)。 - 使用中文回答。 - 生成相关问题。 - 在引用段落末尾添加引用标识,如[^1]。 - 回答结构清晰,逐步解决问题。 用户可见层:确保回答真实可靠,基于提供的引用。 关键点: - 对于Spring Boot应用,可以使用`-Dspring.config.location`指定外部配置文件路径。 - 对于标准Java应用,可以通过类路径文件路径读取配置文件。 - 示例代码演示如何读取文件。 步骤: 1. **解释配置加载顺序**:基于引用[1],Spring Boot有默认的配置加载顺序。 2. **命令行指定配置**:基于引用[2],使用`java -jar`时添加参数。 3. **代码实现**:基于引用[3]和[4],展示如何读取外部文件。 4. **生成相关问题**:在末尾添加相关问题。 最终回答结构: - 开头:重述问题并提供概述。 - 详细解释:分点解释方法。 - 代码示例:提供代码块。 - 注意事项。 - 相关问题。</think>### Java运行时读取同目录下config文件夹中的配置文件Java应用中,通过`java -jar`运行jar包时,读取同目录下config文件夹中的配置文件是一个常见需求。这通常涉及指定外部配置文件路径,避免将配置硬编码到jar包内。以下是逐步解释和实现方法,基于Spring Boot框架(常用)和标准Java应用两种场景。Spring Boot默认支持外部配置加载,而标准Java应用则需要手动处理文件路径。 #### 1. **Spring Boot应用读取外部配置文件** Spring Boot提供了灵活的配置加载机制。默认情况下,它会按特定顺序查找配置文件(如`application.properties``application.yml`),优先级从高到低为: - 命令行参数(如`--spring.config.location`)。 - Jar包外同级目录的`config`文件夹。 - Jar包外同级目录。 - Jar包内`classpath`下的`config`文件夹。 - Jar包内`classpath`根目录[^1]。 要读取同目录下`config`文件夹的配置文件,只需在启动时通过命令行指定路径: - 在jar包同级目录创建`start.bat`(Windows)`start.sh`(Linux)脚本。 - 使用`-Dspring.config.location`参数指向外部文件夹。 **示例命令行(Windows)**: ```bash @echo off title MyApp chcp 65001 # 设置UTF-8编码,避免中文乱码 java -Dfile.encoding=utf-8 -jar your-app.jar --spring.config.location=file:./config/ pause ``` - **解释**: - `--spring.config.location=file:./config/`:指定当前目录下的`config`文件夹作为配置源。`file:`前缀表示文件系统路径。 - `-Dfile.encoding=utf-8`:确保控制台输出中文不乱码。 - 运行后,Spring Boot会自动加载`config`文件夹中的`application.properties``application.yml`文件[^2]。 **注意事项**: - 如果`config`文件夹中有多个配置文件,Spring Boot会按字母顺序加载。 - 在Linux中,使用`start.sh`脚本,内容类似:`java -jar your-app.jar --spring.config.location=file:./config/`。 - 测试时,确保`config`文件夹jar包同级,否则路径需调整为绝对路径(如`D:\your\path\config\`)。 #### 2. **标准Java应用读取外部配置文件** 对于非Spring Boot的普通Java应用,需手动读取文件。推荐使用`java.io.File``java.nio.file.Paths`获取外部路径,避免类路径限制。 **代码示例(读取.properties文件)**: ```java import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; public class ConfigLoader { public static void main(String[] args) { // 获取jar包同级目录下的config文件夹路径 String configDir = System.getProperty("user.dir") + "/config/"; String configFile = configDir + "app.properties"; Properties props = new Properties(); try (FileInputStream fis = new FileInputStream(configFile)) { props.load(fis); String value = props.getProperty("key"); // 读取配置项 System.out.println("配置值: " + value); } catch (IOException e) { System.err.println("加载配置文件失败: " + e.getMessage()); // 回退方案:从jar包内加载默认配置 // props.load(getClass().getResourceAsStream("/default.properties")); } } } ``` - **解释**: - `System.getProperty("user.dir")`:获取当前工作目录(即jar包所在路径)。 - 路径格式:`user.dir/config/app.properties`确保文件jar包外部的`config`文件夹中。 - 异常处理:如果外部文件缺失,可回退到jar包内默认配置(如`classpath`中的文件)[^4][^3]。 **最佳实践**: - **路径处理**:使用`File.separator`替代`/`,确保跨平台兼容(如`String path = System.getProperty("user.dir") + File.separator + "config"`)。 - **配置文件格式**:支持`.properties`、`.yml``.xml`;Spring Boot优先识别YAML。 - **安全考虑**:避免硬编码路径;在Docker容器中,可将`config`文件夹挂载为卷。 #### 3. **常见问题与解决方案** - **问题:配置文件未加载?** - 检查路径是否正确:使用绝对路径测试(如`--spring.config.location=file:D:/app/config/`)。 - 确保文件权限:Linux中运行`chmod`确保jar可读`config`文件夹。 - **问题:中文乱码?** - 添加`-Dfile.encoding=utf-8`参数,并在代码中指定编码(如`new InputStreamReader(fis, StandardCharsets.UTF_8)`)[^2]。 - **问题:多环境配置?** - Spring Boot支持`--spring.profiles.active=prod`激活不同配置;在`config`文件夹中创建`application-prod.yml`文件[^1]。 通过以上方法,您可以灵活管理外部配置,提升应用的可维护性。如果使用Spring Boot,推荐命令行参数方式;标准Java应用则需手动处理路径。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值