IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 在 Java 中,如何批量读取本项目资源目录下的所有文件 -> 正文阅读

[Java知识库]在 Java 中,如何批量读取本项目资源目录下的所有文件

今天笔者遇到一个需求,如何读取本项目资源目录下的所有文件。读取资源目录下的指定的文件很容易,这只需要给出路径即可。

读取资源目录下的指定文件

/**
 * 方法 getResourceAsStream 的路径是以资源目录 resources 为基准的,
 * 且不受 Maven 模块的限制。这于 xxx.class 中 xxx 是哪个模块的哪个类无关
 */
var inputStream = XXX.class.getClassLoader().getResourceAsStream("path/filename.suffix");

但是现在,需要读取资源目录下的所有文件。也就是说,不能指定资源目录下的文件名,最多可以指定基路径。

笔者梳理了一下,这种需求可以分为以下几个实现步骤:

  • 读取本目录下的本级文件与文件夹。

  • 递归读取本目录下本级文件夹内的文件。

这样梳理之后,实现方案就有了。

方法 1:使用 JDK 中原始 API

    /**
     * 读取资源目录中路径 path 下的所有文件。path 不需要以斜杠 / 开头
     *
     * @since 2022-1-16
     */
    public static void readAllResFiles(String path) throws IOException, URISyntaxException {
        var urlEnumeration = ReadAllResFiles.class.getClassLoader().getResources(path);
        // 正常来讲,此循环应该只会进行一次
        while (urlEnumeration.hasMoreElements()) {
            var url = urlEnumeration.nextElement();
            var fileDir = new File(new URI(url.toString()));
            recursiveReadFile(fileDir);
        }
    }

    /**
     * 读取文件或递归读取文件夹内的文件
     *
     * @since 2022-1-16
     */
    public static void recursiveReadFile(File fileOrDir) {
        // 如果一开始传入的 fileOrDir 就为空,直接返回
        if (fileOrDir == null) {
            System.out.println("fileOrDir 为空"); // FIXME:日志
            return;
        }

        if (fileOrDir.isFile()) {
            // 子递归函数将在此处终止
            System.out.println("文件路径:" + fileOrDir); // TODO:对 fileOrDir 进行处理
        } else {
            for (var file : Objects.requireNonNull(fileOrDir.listFiles())) {
                recursiveReadFile(file); // 如果不需要递归遍历子文件夹,可将此处改为对 fileOrDir 的直接处理
            }
        }
    }

??在上面的代码中,方法 readAllResFiles 中入口方法,然后对于具体的业务,可以在方法 recursiveReadFile 中添加。如果使用函数式编程的技术,对外暴露一个需使用者实现的函数式接口,这里都可以直接在无需提前知道具体业务的情况下,以开闭原则完成本方法的实现。关于函数式编程,可见笔者的另一篇博客:

Java 函数式编程入门:
https://blog.csdn.net/wangpaiblog/article/details/122762637

方法 2:借助 Spring

??笔者正当为自己的聪明机智洋洋得意的时候,突然想到一个问题。扫描项目中某目录下的所有文件,这不是 Spring 的基本功能吗?(因为 Spring 支持扫描项目某目录及其子目录下的所有文件,并按要求选择将其注册为 Bean。)也就是说,Spring 应该已经实现了这种功能。

??为了打消这个顾虑,笔者不断查看 Spring 源码,终于发现了这个功能的实现。唉,刚刚吃的夜宵突然就不香了。

??Spring 有一个类 PathMatchingResourcePatternResolver,它有一个方法 getResources 可以实现此功能。具体代码如下:

    /**
     * @since 2022-1-16
     */
    public static void readAllResFiles() throws IOException {
        var resolver = new PathMatchingResourcePatternResolver();

        // 可根据需要进行选择
        var resources = resolver.getResources("classpath:path/*"); // 遍历指定目录下的文件与文件夹,但不把文件夹当做文件处理,不进行深层遍历
//        var resources = resolver.getResources("classpath:path/*.*"); // 遍历目录下所有有文件后缀的文件
//        var resources = resolver.getResources("classpath:path/**"); // 递归遍历目录下的所有文件与文件夹

        for (var resource : resources) {
            // TODO:对 resource 进行处理
            System.out.println(resource.getFilename()); // 文件名
            System.out.println(resource.getURL().getPath()); // 文件绝对路径
            System.out.println(resource.getFile()); // File 对象
            // 如果 resource 不是目录
            if (resource.getFile().isFile()) {
                System.out.println(resource.getInputStream()); // InputStream 对象
            }
        }
    }

??对于 SpringBoot 项目,可以直接使用上述的方法而不需要添加其它依赖。如果项目中原来没有使用过 Spring,则需要添加如下依赖(以 Maven 为例):

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.9.RELEASE</version>
</dependency>

附录

??上面的方法是间接得到了资源文件,通常还需要做进一步的转化,这里给出一些常用的转化操作。

将 InputStream 转化为 byte 数组

    /**
     * 此方法不会重置流,因此经过转化后,原来的流将不能再使用。
     * 因此,如果想要反复读取流,请转化前对流进行备份
     *
     * @since 2021-11-24
     */
    public static byte[] inputStream2byteArray(InputStream inputStream) throws IOException {
        return inputStream.readAllBytes();
    }

??注意:InputStream 对象中的数据是不能直接被反复读取的。通常情况下,InputStream 对象在读取完数据之后将作废。有一些方法可以解决这个问题,可见笔者的另一篇博客:

如何反复读取同一个 InputStream 对象:
https://blog.csdn.net/wangpaiblog/article/details/121369433

将 File 转化为 byte 数组

    /**
     * @since 2021-11-24
     */
    public static byte[] file2byteArray(File file) throws IOException {
        return inputStream2byteArray(new FileInputStream(file));
    }

??其中,方法 inputStream2byteArray 是前面已经提供的函数。

将 byte 数组转化为 InputStream

    /**
     * @since 2021-11-24
     */
    public static InputStream byteArray2InputStream(byte[] bytes) {
        return new ByteArrayInputStream(bytes);
    }
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:19:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:57:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码