通过classLoader批量读取文件(文件夹)遇到的问题

本文介绍如何在Spring Boot应用中批量读取未知数量和名称的资源文件,包括在不同部署环境下(如开发环境与打包成jar后的运行环境)的正确实现方式。
前言
适用springboot 简单搭建了一个小环境,通过classLoader获取classpath下的文件夹中的文件,批量获取文件,也许你不知道有多少文件和文件的名称,基于这个情况下总结了一些经验教训
环境
  1. resource下创建文件夹在这里插入图片描述
    这里创建了2个文件,a 和b , 如果我们确定知道文件名称 就好办了 通过classLoader.getResourceAsStream() 即可获取, 假设我们不知道文件名称和数量

  2. 编写测试类

    错误代码示范\color{red}{错误代码示范}

         // 获取class 根目录
        URL resource = FileJar.class.getClassLoader().getResource("my/file");
        System.out.println(resource.getPath());
        //        获取my/file 下的所有文件
        File[] files = new File(resource.getPath()).listFiles();
        if (files != null) {
        Arrays.stream(files).forEach(e -> System.out.println("file path = " + e.getAbsolutePath()));
    
        }
    

    输出

       /F:/workSpaces/idea/springboot-test/file-jar/target/classes/my/file
    file path = F:\workSpaces\idea\springboot-test\file-jar\target\classes\my\file\a.txt
    file path = F:\workSpaces\idea\springboot-test\file-jar\target\classes\my\file\b.txt
    
    

** 看似没问题,但是打包为jar后输出
file:/F:/workSpaces/idea/springboot-test/file-jar/target/file-jar-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/my/file
是一个压缩文件 jar路径, file 是读取不了的**

正确方式
   Enumeration<URL> resources = FileJar.class.getClassLoader().getResources("my/file");
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            // 通过判断协议是不是jar文件
            if (url.getProtocol().equals("jar")) {
                JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
                JarFile jarFile = urlConnection.getJarFile();
                Enumeration<JarEntry> entries = jarFile.entries(); // 返回jar中所有的文件目录
                while (entries.hasMoreElements()) {
                    JarEntry jarEntry = entries.nextElement();
                    if (!jarEntry.isDirectory() && jarEntry.getName().startsWith("my/file")) {  // 是我们需要的文件类型
                        String name = jarEntry.getName();
                        System.out.println("name  = " + name);
                        InputStream resourceAsStream = FileJar.class.getClassLoader().getResourceAsStream(name);
                        Properties p = new Properties();
                        p.load(resourceAsStream);
                        System.out.println(p);
                    }
                }
            } else if (url.getProtocol().equals("file")) {
                // 获取class 根目录
                URL resource = FileJar.class.getClassLoader().getResource("my/file");
                System.out.println(resource.getPath());
                // 获取my/file 下的所有文件
                File[] files = new File(resource.getPath()).listFiles();
                if (files != null) {
                    Arrays.stream(files).forEach(e -> System.out.println("file path = " + e.getAbsolutePath()));
                }
            }
        }
通过jarFile 来获取jar包中的文件, 如果有其他jar包和你的文件夹命名相同可以添加 url条件进行判断

知识点

ClassLoader.getResource(String name);

ClassLoader.getResource("");  // 获取的是项目根目录,也就是到classes/这一层

ClassLoader.getResources(String name);

ClassLoader.getResources("my/file/a.properties"); // 加载多个jar文件中的 my/file/a.properties 文件, springboot的spring.factories 就是这么加载的

ClassLoader.getResourceAsStream(String name);
Spring Boot 项目中,YAML 配置文件通常用于存储应用程序的配置信息,而 `resources` 文件夹用于存放静态资源、模板文件或外部数据文件(如文本文件、JSON 文件等)。要从 `resources` 文件夹读取文件内容,可以通过以下几种方式实现: ### 1. 使用 `ResourceLoader` 读取文件内容 Spring 提供了 `ResourceLoader` 接口,可以通过它来加载类路径下的资源文件。 ```java import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class ResourceFileReader { private final ResourceLoader resourceLoader; public ResourceFileReader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } public String readFile(String filePath) throws IOException { Resource resource = resourceLoader.getResource("classpath:" + filePath); StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } } return content.toString(); } } ``` 在配置类或控制器中注入 `ResourceLoader` 并调用 `readFile()` 方法即可读取指定路径下的文件内容。 ### 2. 通过 `ClassLoader` 读取资源文件 使用类加载器可以直接从类路径中读取资源文件: ```java import java.io.InputStream; import java.util.Scanner; public class FileLoader { public String loadFile(String filePath) { InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); if (inputStream == null) { throw new RuntimeException("File not found: " + filePath); } Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); return scanner.hasNext() ? scanner.next() : ""; } } ``` 该方法适用于读取文本文件、JSON 文件等非结构化数据。 ### 3. 在 YAML 配置文件中引用资源路径 虽然 YAML 配置文件本身不能直接读取 `resources` 文件夹中的文件内容,但可以在配置文件中指定资源路径,然后在代码中读取该路径对应的文件: ```yaml app: config-file: config/sample.json ``` 然后在 Java 代码中通过 `@Value` 注解注入该路径并读取文件内容: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import java.io.InputStream; public class ConfigLoader { @Value("${app.config-file}") private String configFilePath; public String loadConfigFile() throws IOException { ClassPathResource resource = new ClassPathResource(configFilePath); try (InputStream inputStream = resource.getInputStream()) { return new String(inputStream.readAllBytes()); } } } ``` ### 4. 使用 `@PropertySource` 加载自定义资源文件 如果资源文件是 `.properties` 格式,可以通过 `@PropertySource` 注解加载并注入其内容: ```java @Configuration @PropertySource("classpath:custom.properties") public class PropertyConfig { } ``` 然后在其他组件中使用 `@Value` 注入具体的属性值。 ### 总结 YAML 配置文件本身不支持直接读取 `resources` 文件夹中的内容,但可以通过 Spring 提供的资源加载机制(如 `ResourceLoader`、`ClassLoader`)实现该功能。此外,可以在 YAML 中配置资源路径,再在 Java 代码中读取对应路径的文件内容。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值