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

本文介绍如何在Spring Boot应用中批量读取未知数量和名称的资源文件,包括在不同部署环境下(如开发环境与打包成jar后的运行环境)的正确实现方式。

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

前言
适用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);
<think>好的,用户的问题是关于如何使用Java中的FileInputStream从resources文件夹读取文件的示例代码。我需要先回忆一下Java读取资源文件的常用方法。根据用户提供的引用[1],提到了使用getResourceAsStream或getResource方法,这两个方法通常是通过类加载器来获取资源。但用户特别提到想要用FileInputStream,这可能涉及到直接通过文件路径访问资源。 首先,resources文件夹在构建后通常会被打包到JAR文件中,因此在运行时,如果使用FileInputStream直接访问文件路径,可能会遇到问题,因为JAR内的文件不是普通的文件系统文件。这时候,使用类加载器的getResourceAsStream方法更为可靠,因为它可以从类路径中读取资源,无论资源是在文件系统还是JAR包中。不过用户可能由于某些原因坚持要使用FileInputStream,比如需要File对象或者其他API需要文件路径。 接下来,我需要检查引用中的信息。引用[1]提到使用getResourceAsStream或getResource,而引用[2]中的代码片段涉及FileSystem和URI的处理,可能在处理文件系统时有用。引用[3]和[4]似乎与当前问题关联不大,但需要确认是否有其他相关信息。 用户可能需要明确的示例代码,展示如何使用FileInputStream读取resources中的文件。首先需要明确,当应用程序运行时,资源文件可能位于类路径的某个位置,比如在IDE中,resources文件夹通常会被复制到输出目录(如target/classes或build/resources/main)。这时候,可以使用相对路径或绝对路径来访问,但这种方法在打包成JAR后可能失效,因为JAR内的文件无法用File直接访问。 因此,正确的做法应该是通过类加载器获取资源的URL,然后将其转换为URI,再用Paths.get(URI)来获取Path对象,进而转换为File。不过需要注意,如果资源在JAR内,这种方法会抛出异常,因为JAR协议的文件系统可能需要特殊处理,如引用[2]中的代码所示,可能需要创建新的文件系统。 所以,可能的步骤是:使用getResource方法获取URL,转换为URI,处理可能的异常,然后使用Paths.get来获取正确的路径,从而创建FileInputStream。例如: URL resourceUrl = getClass().getClassLoader().getResource("example.txt"); if (resourceUrl != null) { try { Path path = Paths.get(resourceUrl.toURI()); File file = path.toFile(); FileInputStream fis = new FileInputStream(file); // 读取文件内容... } catch (Exception e) { e.printStackTrace(); } } 但需要注意,当资源在JAR中时,resourceUrl.toURI()可能会是类似jar:file://...的URI,这时直接转换为Path会失败,需要特殊处理,如引用[2]中的FileSystem处理。因此,需要分情况处理:如果URI是jar协议,则需先打开文件系统,再获取路径。 不过,这样的处理可能比较复杂,因此通常推荐使用getResourceAsStream直接获取输入流,而不是使用FileInputStream。但用户明确要求使用FileInputStream,所以必须处理这些情况。 总结:示例代码需要展示如何正确获取资源文件的路径,并处理JAR内和文件系统两种情况。同时要提醒用户这种方法的局限性,可能推荐更可靠的方法。</think>### 使用`FileInputStream`读取`resources`文件夹文件的示例代码 在Java中,从`resources`文件夹读取文件时,**若项目未打包成JAR**,可以通过`FileInputStream`直接访问资源路径;**若已打包成JAR**,则需通过`ClassLoader`获取资源路径并处理URI格式差异[^1][^2]。以下是具体实现步骤: --- #### **步骤1:获取资源路径** 通过`ClassLoader`获取资源的绝对路径: ```java // 示例文件路径:src/main/resources/example.txt String fileName = "example.txt"; URL resourceUrl = getClass().getClassLoader().getResource(fileName); if (resourceUrl == null) { throw new FileNotFoundException("资源文件未找到: " + fileName); } ``` --- #### **步骤2:处理URI格式** 将资源URL转换为`Path`对象: ```java try { // 转换URL为URI(处理空格等特殊字符) URI uri = resourceUrl.toURI(); Path path; // 判断是否为JAR内部路径(需特殊处理) if (uri.getScheme().equals("jar")) { // 初始化JAR文件系统(参考引用[2]) FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap()); path = fileSystem.getPath("/" + fileName); } else { // 普通文件系统路径 path = Paths.get(uri); } // 创建FileInputStream try (FileInputStream fis = new FileInputStream(path.toFile())) { // 读取文件内容(示例:逐行读取) BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } } } catch (URISyntaxException | IOException e) { e.printStackTrace(); } ``` --- ### **注意事项** 1. **JAR打包后的限制** 若文件在JAR内部,直接使用`FileInputStream`可能失败,需通过`FileSystem` API动态加载JAR内容。 2. **更推荐的替代方案** 使用`ClassLoader.getResourceAsStream()`更简单且兼容性强: ```java try (InputStream is = getClass().getClassLoader().getResourceAsStream(fileName)) { // 直接读取输入流 } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值