📋 目录
一、工具类功能
在一个目录里递归找文件,按扩展名、大小、最后修改时间、文件名关键字过滤或组合筛选,也能一次统计出文件数与总字节数,拿回来是不可变的路径列表与统计结果。
二、所需环境
JDK 17或以上
三、方法与调用示例(按需调用)
🔢 方法序号:1
🎯 方法用途:
- 递归一个目录,列出全部普通文件
- 清理上传目录、批量取某类文件前先拿到全量清单时用
🧩 方法定义:public static List<Path> listFiles(Path root)
🗣️ 入参解释:public static List<Path> listFiles(根目录)
📤 返回值解释:List<Path>,不可变列表,只有普通文件
💡 边界口径:
- 目录条目永远不出现在结果里,按关键字搜目录名也是空
- 顺序是遍历侧的产出顺序,不保证跨平台一致,要稳定顺序自己排序
- 根为 null、不存在或是文件而非目录,都在开始遍历前抛
IllegalArgumentException - 默认不跟随符号链接,但指向普通文件的链接会被算作普通文件
🧪 方法示例:
listFiles(root)递归出7 个普通文件- 结果里有
LICENSE、note.txt、photo.jpg、report.txt,也有子目录里的backup.zip - 根路径给成一个文件时抛
root 目录不存在或不是目录
🔢 方法序号:2
🎯 方法用途:
- 限定最大深度地递归列文件,只扫当前层或前几层
- 目录树很深、或者只想处理根目录这一层文件时用
🧩 方法定义:public static List<Path> listFiles(Path root, int maxDepth)
🗣️ 入参解释:public static List<Path> listFiles(根目录, 最大深度)
📤 返回值解释:List<Path>,深度内的普通文件不可变列表
💡 边界口径:
maxDepth为 1 只取根目录这一层的文件maxDepth为 0 连根这一层都不取,返回空列表- 传负数抛
IllegalArgumentException,消息带上实际值 - 拿不准目录结构时别用不限深度,限深更稳
🧪 方法示例:
listFiles(root, 1)拿到LICENSE, note.txt, photo.jpg, report.txt,只剩根这一层listFiles(root, 0)拿到0 个maxDepth传 -1 抛maxDepth不能为负数,当前为-1
🔢 方法序号:3
🎯 方法用途:
- 按扩展名批量取文件,跨层级、忽略大小写
- 只处理日志、只导出图片这类按后缀筛选的动作用它
🧩 方法定义:public static List<Path> listByExtension(Path root, String... extensions)
🗣️ 入参解释:public static List<Path> listByExtension(根目录, 扩展名若干)
📤 返回值解释:List<Path>,命中后缀的普通文件不可变列表
💡 边界口径:
- 扩展名取最后一个点之后的整段并忽略大小写,入参带不带点都行
gz命中data.tar.gz却不会命中a.mgz,tar也命不中data.tar.gz,要精确匹配复合后缀就整个写tar.gz- 没有扩展点的文件(
LICENSE)不属于任何扩展名 - 集合为空或含 null、空白项都抛
IllegalArgumentException
🧪 方法示例:
listByExtension(root, "txt")拿到report2023.txt, note.txt, report.txt,跨层级且不看大小写listByExtension(root, "gz")拿到data.tar.gz,按整段后缀命中- 换成
tar一个也取不到,拿到0 个 - 按
license找那个没有扩展点的文件,拿到0 个 - 扩展名给空集合抛
extensions 不能为空,至少需要一个扩展名 - 扩展名里夹一个空白项抛
extensions 不能包含null或空白项
🔢 方法序号:4
🎯 方法用途:
- 列出严格大于某字节数的文件,找大文件、清理占空间的附件
- 按体积筛文件时用,注意是严格大于
🧩 方法定义:public static List<Path> listLargerThan(Path root, long minBytes)
🗣️ 入参解释:public static List<Path> listLargerThan(根目录, 字节下限)
📤 返回值解释:List<Path>,体积超过阈值的文件不可变列表
💡 边界口径:
- 判定是严格大于,刚好等于阈值的文件不在结果里
- 与
search里的minBytes(大于等于)口径不同,别混用 - 阈值传负数抛
IllegalArgumentException - 单个文件读不到大小按不匹配跳过,不报错
🧪 方法示例:
listLargerThan(root, 50)拿到backup.zip, report.txt,严格大于 50 字节- 刚好 50 字节的
photo.jpg不算,结果里没有它 - 阈值给 -1 抛
minBytes不能为负数,当前为-1
🔢 方法序号:5
🎯 方法用途:
- 列出严格小于某字节数的文件,挑出空文件、被截断的碎片
- 清理无意义小文件时用,口径与上一个相反
🧩 方法定义:public static List<Path> listSmallerThan(Path root, long maxBytes)
🗣️ 入参解释:public static List<Path> listSmallerThan(根目录, 字节上限)
📤 返回值解释:List<Path>,体积小于阈值的文件不可变列表
💡 边界口径:
- 判定是严格小于,等于阈值的文件不入选
- 空文件(0 字节)会被列出来
- 属性读不到的文件按不匹配跳过
🧪 方法示例:
listSmallerThan(root, 10)拿到LICENSE, note.txt,严格小于 10 字节- 10 字节的
report2023.txt不算在内
🔢 方法序号:6
🎯 方法用途:
- 列出最后修改时间严格晚于阈值的文件
- 增量处理「最近改过的文件」时用这一版
🧩 方法定义:public static List<Path> listModifiedAfter(Path root, Instant threshold)
🗣️ 入参解释:public static List<Path> listModifiedAfter(根目录, 时间阈值)
📤 返回值解释:List<Path>,阈值之后改过的文件不可变列表
💡 边界口径:
- 判定是严格晚于,等于阈值的文件不算
- 阈值传 null 抛
IllegalArgumentException - 修改时间读不到的文件按不匹配跳过
🧪 方法示例:
listModifiedAfter(root, 一天前)拿到LICENSE, note.txt, photo.jpg, report.txt,都是最近一天内改过的
🔢 方法序号:7
🎯 方法用途:
- 列出最后修改时间严格早于阈值的文件
- 归档陈旧文件、按时间清理历史产物时用
🧩 方法定义:public static List<Path> listModifiedBefore(Path root, Instant threshold)
🗣️ 入参解释:public static List<Path> listModifiedBefore(根目录, 时间阈值)
📤 返回值解释:List<Path>,阈值之前改过的文件不可变列表
💡 边界口径:
- 判定是严格早于,等于阈值的不算,与方法6 成对
- 阈值传 null 抛
IllegalArgumentException - 目录条目不参与判断,结果里只有普通文件
🧪 方法示例:
listModifiedBefore(root, 十天前)拿到backup.zip, data.tar.gz, report2023.txt,都是十天之前改过的- 时间阈值本身不参与匹配,Demo 日志的原话是
口径都是严格比较,等于阈值的不算
🔢 方法序号:8
🎯 方法用途:
- 按文件名关键字包含匹配搜文件
- 只记得名字里有一段时用,比手写通配省事
🧩 方法定义:public static List<Path> searchByName(Path root, String keyword)
🗣️ 入参解释:public static List<Path> searchByName(根目录, 文件名关键字)
📤 返回值解释:List<Path>,文件名含关键字的普通文件
💡 边界口径:
- 匹配的是文件名,不看目录名,搜目录名永远为空
- 关键字为 null 或空白抛
IllegalArgumentException - 是包含匹配,不是通配也不是正则
🧪 方法示例:
searchByName(root, "report")拿到report2023.txt, report.txt,跨层级包含匹配- 关键字给空白串抛
keyword 不能为null或空白
🔢 方法序号:9
🎯 方法用途:
- 扩展名、体积、修改时间三个条件组合搜索,深度不限
- 「近一天改过的、不小于 100 字节的 txt」这类复合筛选用它
🧩 方法定义:public static List<Path> search(Path root, Collection<String> extensions, Long minBytes, Instant modifiedAfter)
🗣️ 入参解释:public static List<Path> search(根目录, 扩展名集合, 字节下限, 时间阈值)
📤 返回值解释:List<Path>,同时满足各条件的文件
💡 边界口径:
minBytes是大于等于,与listLargerThan的严格大于不同,别混用extensions传 null 表示不限扩展名,传了就不能为空集合或含空白项minBytes、modifiedAfter允许 null,表示该维度不设限- 各条件之间是与的关系,全部通过才入选
🧪 方法示例:
search(root, List.of("txt"), 100L, 一天前)拿到report.txt,三个条件同时命中- 这里的
minBytes是大于等于,正好 100 字节的文件也会入选
🔢 方法序号:10
🎯 方法用途:
- 组合搜索并限定最大深度,条件同四参版
- 大目录树里只扫前几层时用这一版
🧩 方法定义:public static List<Path> search(Path root, Collection<String> extensions, Long minBytes, Instant modifiedAfter, int maxDepth)
🗣️ 入参解释:public static List<Path> search(根目录, 扩展名集合, 字节下限, 时间阈值, 最大深度)
📤 返回值解释:List<Path>,深度内满足条件的文件
💡 边界口径:
- 深度从 1 起算,超出层级的文件不参与条件判断
- 其余条件与四参版一致,包括
minBytes的大于等于口径 maxDepth为负抛IllegalArgumentException
🧪 方法示例:
- 同样条件但
maxDepth给 1,拿到note.txt, report.txt - 四层深的
report2023.txt就不在结果里了
🔢 方法序号:11
🎯 方法用途:
- 统计目录里的普通文件数与总字节数
- 上报容量、判断目录是否空转、清理前后对比时用
🧩 方法定义:public static DirStats stats(Path root)
🗣️ 入参解释:public static DirStats stats(根目录)
📤 返回值解释:DirStats,含 fileCount 与 totalBytes 的记录
💡 边界口径:
- 只算普通文件,目录条目不计
- 属性读不到的文件按 0 字节计入数量,这是「文件明明在却没统计到大小」时的解释
- 空目录返回 0 个文件、0 字节,不抛异常
- 根不合法仍抛
IllegalArgumentException
🧪 方法示例:
stats(root)拿到普通文件 7 个、共 3191 字节
🔢 方法序号:12
🎯 方法用途:
- 手工装配一份统计结果,把外部采集到的数量与字节数装进同一结构
- 与
stats返回的是同一个记录类型,下游处理不用分叉
🧩 方法定义:public record DirStats(long fileCount, long totalBytes)
🗣️ 入参解释:public record DirStats(文件数, 总字节数)
📤 返回值解释:DirStats,不可变的统计记录
💡 边界口径:
- 构造时不做负数校验,两个字段原样保存
averageBytes()在文件数为 0 时给 0,不会抛除零异常- 是 record,同数值两份对象判等成立
🧪 方法示例:
new DirStats(3, 300)之后调averageBytes()拿到平均 100 字节new DirStats(0, 0)的平均值拿到0 个文件时平均取 0 不抛除零
🔢 方法序号:13
🎯 方法用途:
- 取统计结果里每个文件的平均字节数
- 判断目录里是不是塞了一堆空文件、或者平均体积异常时用
🧩 方法定义:public long averageBytes()
🗣️ 入参解释:public long averageBytes()(无入参)
📤 返回值解释:long,总字节数除以文件数,文件数为 0 时给 0
💡 边界口径:
- 整数除法向下取整,不做四舍五入
- 分母是
fileCount,与stats的跳过口径一致 - 不抛异常,空目录安全
🧪 方法示例:
stats(root).averageBytes()拿到平均每个文件 455 字节,3191 除以 7 向下取整
四、工具类源码(可直接复制)
📦 源码文件