【开发】SpringBoot如何优雅的读取Resources下的文件

如何优雅的读取Resources下的文件


前言

前些日子同事遇到了一个问题:在开发中读取resources/template/template.xls文件是可行的,但是打包放到环境上就不可行了,虽然最后解决了,但是我觉得方式不够优雅,在这里记录一下几种读取resources文件的方式。

注意:下面列的几种方法有些只能在开发代码的时候使用(打包后无法使用),有些两种环境均可使用,前者我会用红字标出,后者我用绿字做好记号,请注意分辨。

实验性项目已提交至Github,可以下载自行实验: https://github.com/JimLearnSpace/ResourceFileDemo


解决方案s

注意:在测试代码中所有的解决方案最终目的是获取一张图片的文件流,我这里选择将图片显示到浏览器的方式。


方法一 | 使用getClassLoader().getResourceAsStream()(推荐)

环境:开发中/打包后 均可使用

  1. 关键代码this.getClass().getClassLoader().getResourceAsStream("static/b.jpg");
  2. 可以读取resources下的文件,也可以读取resources/xxx(子文件夹)下的文件
  3. 如果要访问resources下的文件,则直接在getResourceAsStream()的括号中写入文件名即可(参考情况1)
  4. 如果要访问resources/xxx/yyy.png(reources下的子文件夹中的文件),则在getResourceAsStream()括号中写入xxx/yyy.png即可(参考情况3)
  5. 注意:在getResourceAsStream()括号中写入xxx\\yyy.png可以在Windows开发环境中访问resources/xxx/yyy.png文件,但是这种方式只能在开发的时候使用,打包后无法使用(参考情况2)
public void method1(HttpServletResponse response) throws IOException {
    /* -- 情况1 | 访问resources下的文件 -- */
    // InputStream in = this.getClass().getClassLoader().getResourceAsStream("a.png");
    /* -- 情况2 | 访问resources/static下的文件(Windows开发中)-- */
    // InputStream in = this.getClass().getClassLoader().getResourceAsStream("static\\a.png");
    /* -- 情况3 | 访问resources/static下的文件(开发中/打包后) -- */
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("static/b.jpg");
    
    /* 以上代码已经获取文件流成功,下面的代码是为了将文件流返回给浏览器 */
    HttpServletUtils.View(response);
    log.info("访问method4/InputStream");
    FileCopyUtils.copy(in, response.getOutputStream());
}

由于是第一个示例,我觉得有必要对上述代码作简要说明:

  1. 方法的入参是一个HttpServletResponse,这是为了将文件流返回给浏览器
  2. 代码中有一行HttpServletUtils.View(response);,这是我自己定义的工具类,为了将图片在浏览器中显示(而不是下载)
  3. FileCopyUtils.copy(in, response.getOutputStream());是为了将文件流放到response中,然后返回给浏览器
  4. 因此这一段代码真正有效的是InputStream in开头的代码,其中注释掉的几行是访问不同的文件

方式二 | getResourceAsStream()(推荐)

环境:开发中/打包后 均可使用

  1. 关键代码this.getClass().getResourceAsStream("/a.png");
  2. 可以读取resources下的文件,也可以读取resources/xxx(子文件夹)下的文件
  3. 如果要访问resources下的文件,则直接在getResourceAsStream()的括号中写入/文件名即可(参考情况1)
  4. 如果要访问resources/xxx/yyy.png(reources下的子文件夹中的文件),则在getResourceAsStream()括号中写入/xxx/yyy.png即可(参考情况2)
  5. 注意:不可以使用\\xxx\\yyy.png的方式访问reources/xxx/yyy.png文件
public void method2(HttpServletResponse response) throws IOException {
    // 情况1 | 访问resources下的文件
    InputStream in = this.getClass().getResourceAsStream("/a.png");
    // 情况2 | 访问rources/static下的文件
    // InputStream in = this.getClass().getResourceAsStream("/static/a.png");

    /* 以上代码已经获取文件流成功,下面的代码是为了将文件流返回给浏览器 */
    HttpServletUtils.View(response);
    FileCopyUtils.copy(in, response.getOutputStream());
}

方式三 | 使用new ClassPathResource("static/a.png")获取资源(推荐)

环境:开发中/打包后 均可使用

这种方式本质上是获取一个ClassPathResource资源文件,随后通过getInputStream的方式获取该资源文件的文件流。

  1. 关键代码ClassPathResource classPathResource = new ClassPathResource("xxx/yyy.png")
  2. 可以读取resources下的文件,也可以读取resources/xxx(子文件夹)下的文件
  3. 如果要访问resources下的文件,则直接在new ClassPathResource()的括号中写入文件名即可(参考情况1)
  4. 如果要访问resources/xxx/yyy.png(reources下的子文件夹中的文件),则在new ClassPathResource()括号中写入xxx/yyy.png即可(参考情况2)
  5. 注意:也可以使用xxx\\yyy.png的方式访问reources/xxx/yyy.png文件,但是仅限于在开发过程中,且只能Windows上使用。
public void method3(HttpServletResponse response) {
    /* 设置请求头(与读取文件无关,请忽略) */
    HttpServletUtils.View(response);

    try{
        /* 情况1 | 获取resources下的文件*/
        // ClassPathResource classPathResource = new ClassPathResource("a.png");
        /* 情况2 | 获取rosources/static下的文件 */
        ClassPathResource classPathResource = new ClassPathResource("static/a.png");
        // 获取文件流
        InputStream in = classPathResource.getInputStream();
        FileCopyUtils.copy(in, response.getOutputStream());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

方式四 | 获取resources文件夹的绝对路径(拼接)(不推荐)

仅在开发中可使用,打包后不可使用

  1. 通过关键代码this.getClass().getClassLoader().getResource("").getPath();获取**资源文件夹(resources)**的路径
  2. 在资源文件路径上拼接上要访问的文件名称或路径,获得全路径,随后读取该文件
  3. 因为打包后是个jar包(本质上是一个压缩包),这会成为访问的屏障,但是可以通过zip4j工具类访问(过于麻烦,直接PASS)
  4. 若要访问resources下的文件,只需要拼接上该文件名即可(参考情况1)
  5. 若要访问resources/xxx/yyy.png下的文件,只需要拼接上子文件夹名称/文件名即可(参考情况2)

该方式只要获取到我们要访问的文件路径即视为成功

public void method4(HttpServletResponse response) throws IOException {

    /**/
    String path = this.getClass().getClassLoader().getResource("").getPath();//注意getResource("")里面是空字符串
    /* 情况1 | 获取resources下的文件*/
    // path += "a.png";
    /* 情况2 | 获取resources/static下的文件*/
    path += "static/a.png";
    
    // 获取文件流
    File file = new File(path);
    InputStream in = Files.newInputStream(file.toPath());

    // 返回给浏览器
    HttpServletUtils.View(response);
    FileCopyUtils.copy(in, response.getOutputStream());

}

方式五 | 获取资源文件的绝对路径(不推荐)

仅在开发中可使用,打包后不可使用

  1. 通过关键代码this.getClass().getClassLoader().getResource("文件名").getPath();获取资源文件的路径
  2. 与情况4一致,会被jar包阻挡
  3. 若要访问resources下的文件,只需要在括号内写上文件名即可(参考情况1)
  4. 若要访问resources/xxx/yyy.png下的文件,只需要在括号内写上子文件夹名称/文件名即可(参考情况2)

该方式只要获取到我们要访问的文件路径即视为成功

public void method5(HttpServletResponse response) throws IOException {
    /* 情况1 | 访问resources下的文件 */
    // String filePath = this.getClass().getClassLoader().getResource("a.png").getPath();
    /* 情况1 | 访问resources子文件夹下的文件 */
    String filePath = this.getClass().getClassLoader().getResource("static/a.png").getPath();

    // 获取文件流并返回给前端
    HttpServletUtils.View(response);
    File file = new File(filePath);
    FileCopyUtils.copy(Files.newInputStream(file.toPath()), response.getOutputStream());
}

方式六 | 方式五类似(不推荐)

仅在开发中可使用,打包后不可使用

将方式五的.getPath()改为.getFile(),也可以获取资源文件路径。其余的与方式五没有任何区别

public void method6(HttpServletResponse response) throws IOException {
    String filePath = this.getClass().getClassLoader().getResource("a.png").getFile();
    log.info("当前访问路径:{}",filePath);

    // 通过response控制当前返回状态为:预览
    HttpServletUtils.View(response);

    // 获取文件流并返回给前端
    File file = new File(filePath);
    FileCopyUtils.copy(Files.newInputStream(file.toPath()), response.getOutputStream());
}

方式七 | 通过System.getProperty("user.dir")获取绝对路径(不推荐)

仅在开发中可使用,打包后不可使用

与方式4/5/6没有本质区别,只不过换了一个获取绝对路径的方式

public void method7(HttpServletResponse response) throws IOException {
    String path = System.getProperty("user.dir") + "/src/main/resources/a.png";
    
    // 通过response控制当前返回状态为:预览
    HttpServletUtils.View(response);

    // 获取文件流并返回给前端
    File file = new File(filePath);
    FileCopyUtils.copy(Files.newInputStream(file.toPath()), response.getOutputStream());
}



致谢

本文章参考优快云博主leo825…的博文,文章中还提到了方法七与方法八,但是与4/5/6/7方法没什么太大的区别,这里做了省略。

本文在原博文的基础上做了实验与补充,希望可以帮助到各位。

实验Demo获取方式:Github

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值