看完!我不允许你还不知道 Spring Boot如何读取Resource目录文件

看完!我不允许你还不知道Spring Boot如何读取Resource目录文件

1. 前言

在Spring Boot开发中,我们经常需要读取src/main/resources目录下的文件,src/main/resources 目录下通常存放配置文件、模板、静态资源、SQL脚本等,如何在运行时读取这些资源,是每个JAVA开发者必须掌握的技能。

在这里插入图片描述

比如下面的Spring Boot项目中,资源文件的存储位置:

src/
└── main/
    └── resources/
        ├── static/    # 静态资源
        ├── templates/ # 模板文件
        ├── config/    # 配置文件
        └── data/      # 数据文件

本文博主将将从多种角度详细介绍在 Spring Boot中读取类路径(classpath)下资源的方法,并给出完整的代码示例,相信小伙伴们看完一定能掌握这个技巧!


2. 读取Resource文件的五种常见方式

2.1 使用 ClassPathResource(推荐)

Spring 提供了 ClassPathResource,可直接从类路径获取资源

import org.springframework.core.io.ClassPathResource;
import org.springframework.util.FileCopyUtils;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

public class ResourceReader {
    
    public String readWithClassPathResource(String filePath) throws Exception {
        ClassPathResource resource = new ClassPathResource(filePath);
        try (InputStreamReader reader = new InputStreamReader(
                resource.getInputStream(), StandardCharsets.UTF_8)) {
            return FileCopyUtils.copyToString(reader);
        }
    }
}

测试示例:

String content = readWithClassPathResource("data/sample.txt");
System.out.println(content);
2.2 使用 ResourceLoader

ResourceLoaderSpring 上下文提供的通用资源加载接口,支持多种前缀(classpath:、file:、http: 等

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Component
public class ResourceService {
    
    private final ResourceLoader resourceLoader;
    
    public ResourceService(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
    
    public String readWithResourceLoader(String location) throws Exception {
        Resource resource = resourceLoader.getResource(location);
        try (InputStream in = resource.getInputStream()) {
            byte[] bytes = in.readAllBytes();
            return new String(bytes, StandardCharsets.UTF_8);
        }
    }
}

测试示例:

// 读取 classpath 下的 sample.txt
String text = resourceLoaderService.readWithResourceLoader("classpath:data/sample.txt");

2.3 使用 @Value 注解

如果只是读取小片段文本或 URL,可直接在字段或方法参数上使用 @Value

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Component
public class ValueResourceReader {
    
    @Value("classpath:data/sample.txt")
    private Resource configFile;
    
    public String readConfig() throws IOException {
        return new String(configFile.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
    }
}
2.4 使用 ResourceUtils

ResourceUtilsSpring 内置的一个工具类, 可以将类路径资源转换为 FileURL,适用于需要 java.io.File 操作的场景

import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;

@Service
public class ResourceUtilsService {

    public String readWithResourceUtils(String location) throws Exception {
        // location 形如:"classpath:data/sample.txt"
        File file = ResourceUtils.getFile(location);
        byte[] bytes = Files.readAllBytes(file.toPath());
        return new String(bytes, StandardCharsets.UTF_8);
    }
}
2.5 通过 getResourceAsStream

最原生的方式:通过 ClassClassLoadergetResourceAsStream

import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;

@Service
public class NativeStreamService {

    public String readWithGetResourceAsStream(String path) {
        try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(path);
             BufferedReader reader = new BufferedReader(
                 new InputStreamReader(in, StandardCharsets.UTF_8))) {
            return reader.lines().collect(Collectors.joining(System.lineSeparator()));
        } catch (Exception e) {
            throw new RuntimeException("读取资源失败", e);
        }
    }
}

补充:读取Properties文件

有小伙伴说,读取的配置文件是Properties文件,要如何来读取?下面博主做一个补充,依然使用 ClassPathResource 读取文件

import org.springframework.core.io.ClassPathResource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class PropertiesReader {
    
    public Properties readProperties(String filePath) throws IOException {
        ClassPathResource resource = new ClassPathResource(filePath);
        try (InputStream input = resource.getInputStream()) {
            Properties properties = new Properties();
            properties.load(input);
            return properties;
        }
    }
}

3. 完整实战案例:读取CSV文件并处理

下面我们通过一个实战案例,来加深小伙伴的理解

3.1 创建测试文件

src/main/resources/data/ 下创建users.csv:

id,name,email
1,张三,zhangsan@example.com
2,李四,lisi@example.com
3.2 创建CSV处理器
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

@Service
public class CsvService {
    
    public List<User> parseCsv(String filePath) throws Exception {
        ClassPathResource resource = new ClassPathResource(filePath);
        List<User> users = new ArrayList<>();
        
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(resource.getInputStream()))) {
            
            // 跳过标题行
            String line = reader.readLine();
            
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",");
                if (parts.length == 3) {
                    users.add(new User(
                        Integer.parseInt(parts[0]),
                        parts[1],
                        parts[2]
                    ));
                }
            }
        }
        return users;
    }
    
    public static class User {
        private int id;
        private String name;
        private String email;
        
        // 构造方法、getters和toString
    }
}
3.3 创建Controller测试
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class CsvController {
    
    private final CsvService csvService;
    
    public CsvController(CsvService csvService) {
        this.csvService = csvService;
    }
    
    @GetMapping("/users")
    public List<CsvService.User> getUsers() throws Exception {
        return csvService.parseCsv("data/users.csv");
    }
}

启动应用后访问:http://localhost:8080/users

输出结果
看到输出如下数据证明已经读取成功

[
  {
    "id": 1,
    "name": "张三",
    "email": "zhangsan@example.com"
  },
  {
    "id": 2,
    "name": "李四",
    "email": "lisi@example.com"
  }
]

4. 常见问题解决方案

问题1:文件路径错误

错误信息:java.io.FileNotFoundException: class path resource [xxx] cannot be opened because it does not exist

解决方案:

检查文件是否在src/main/resources目录下
使用正确路径(区分大小写)
文件路径前不要加/(正确:data/file.txt,错误:/data/file.txt)

问题2:打包后文件读取失败

错误信息:FileNotFoundException when reading from JAR

解决方案:

使用ClassPathResource而不是File
避免使用new File(“classpath:…”)语法
使用getResourceAsStream()方法

问题3:读取Resource目录文件中文乱码

解决方案:

// 明确指定UTF-8编码
new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8);

5. 总结

Spring Boot提供了多种灵活的方式来读取resource目录下的文件。根据不同场景选用最合适的方式:

  • 如果需要 Spring 统一管理,推荐 ResourceLoader
  • 若只是简单注入小文件,可选 @Value;
  • 如果需要操作 File,可用 ResourceUtils。

掌握这些方法,能让小伙伴们在处理配置、模板、静态资源等场景时更得心应手,如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!


专栏最新回顾
【01】ThreadLocal的原理以及实际应用技巧详解 - 如何在身份认证场景Token中传递获取用户信息
【02】基于MyBatis-Plus Dynamic-Datasource实现 SaaS 系统动态租户数据源管理
【03】基于nacos实现动态线程池设计与实践:告别固定配置,拥抱弹性调度
【04】Java常用加密算法详解与实战代码 - 附可直接运行的测试示例
【05】Java synchronized 锁机制深度解析与实战指南 - 银行转账案例
【06】还在为线上BUG苦苦找寻?试试IntelliJ IDEA远程调试线上Java程序
【07】使用 Apache Commons Exec 自动化脚本执行实现 MySQL 数据库备份
【08】JAVA开发中几个常用的lambda表达式!记得收藏起来哦~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值