登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  java教程

DirectoryStream glob 怎样过滤文件

来源:17golang原创

时间:2026-10-25 13:18:16 421浏览 收藏

如果任务只是“从一个目录里拿到指定后缀的文件”,Java NIO 不需要先把所有目录项读出来再手动判断。直接使用 Files.newDirectoryStream(dir, glob),就能在打开目录流时按目录项的文件名应用 glob 模式。

官方文档:https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/nio/file/Files.html

最常用的结论是:glob 负责当前目录中的文件名匹配,DirectoryStream 负责遍历和资源生命周期;它不会自动递归子目录,也不会替你判断“必须是普通文件”。

先用 glob 过滤当前目录

Files.newDirectoryStream(Path dir, String glob) 返回一个开放的 DirectoryStream。文档定义的匹配对象是目录项文件名的字符串表示,因此 *.log 表示当前目录下名称以 .log 结尾的目录项。

import java.io.IOException;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;

Path dir = Path.of("/data/inbox");

try (DirectoryStream stream =
         Files.newDirectoryStream(dir, "*.log")) {
    for (Path entry : stream) {
        // entry 是匹配到的目录项;需要普通文件时再做属性判断
        if (Files.isRegularFile(entry)) {
            System.out.println(entry.getFileName());
        }
    }
} catch (IOException | DirectoryIteratorException ex) {
    // 打开目录或迭代期间的 I/O 问题统一交给上层处理
    throw new IllegalStateException("读取日志目录失败", ex);
}
Path、glob、DirectoryStream 和文件名匹配之间的静态关系说明图
图1:DirectoryStream glob 调用关系说明图,查看目录、匹配模式、目录流和目录项之间的静态关系;这是原创结构说明图,不是运行截图。

示例里额外调用了 Files.isRegularFile,是因为 glob 只完成名称匹配,匹配结果仍可能包含目录或其他文件系统目录项。若业务只关心名称,可以直接处理 entry;若关心文件类型,再增加这个判断。

常见 glob 模式怎么选

glob 的具体语法由文件系统的 PathMatcher 规则解释。写目录过滤时,优先让模式只表达名称条件,避免把文件内容、大小或权限判断硬塞进 glob。

模式表达的名称条件适合场景
*.log任意前缀、以 .log 结尾收集一种后缀的日志文件
report-??.csvreport- 后接两个字符,再以 .csv 结尾固定长度编号文件
*.{java,class}匹配多个后缀同时读取 Java 源文件和字节码文件名
backup-*以指定前缀开头筛选一组备份目录项

花括号模式适合把几个已知后缀写在一起,但它仍然是文件名匹配,不代表这些目录项一定是普通文件。模式不合法时,创建目录流会抛出 PatternSyntaxException;不要把用户输入未经约束地拼进模式。

资源关闭和异常边界要一起处理

DirectoryStream 是需要关闭的资源,推荐使用 try-with-resources。目录打开阶段的错误通常以 IOException 暴露;迭代器不能直接声明抛出受检的 I/O 异常,因此迭代阶段可能出现 DirectoryIteratorException,需要从它的 cause 中继续定位底层问题。

import java.io.IOException;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;

static void printJavaFiles(Path dir) {
    try (DirectoryStream stream =
             Files.newDirectoryStream(dir, "*.{java,class}")) {
        // 流只覆盖 dir 的直接目录项,不会自动进入子目录
        for (Path entry : stream) {
            System.out.println(entry);
        }
    } catch (DirectoryIteratorException ex) {
        // 迭代器把底层 I/O 异常包装在 cause 中
        throw new IllegalStateException("遍历目录项失败", ex.getCause());
    } catch (IOException ex) {
        // 目录无法打开、关闭失败等问题走这里
        throw new IllegalStateException("打开目录失败", ex);
    }
}

这里的注释只说明资源、范围和错误处理这几个关键点。实际项目中还应决定是向上抛出异常、记录后跳过,还是把错误转换成业务结果;不要因为 glob 写得简单,就省略目录权限和路径不存在的处理。

glob、Filter 和递归遍历怎么取舍

三种写法解决的问题不同,不能只按“哪种更强”来选:

  • 只按文件名筛当前目录:使用 newDirectoryStream(dir, "*.log"),表达最直接,目录流生命周期也清晰。
  • 还要判断属性或组合条件:使用 DirectoryStream.Filter,例如同时判断普通文件、隐藏状态或名称之外的属性。
  • 必须进入子目录:使用 Files.walk 等递归遍历 API,再把匹配条件放在遍历结果上;不要误以为 DirectoryStream 的 glob 会自动向下搜索。
glob 当前目录过滤、自定义 Filter 和递归遍历之间的边界说明图
图2:glob 与过滤范围边界说明图,比较当前目录名称匹配、自定义条件和递归子目录的职责;这是原创结构说明图,不是运行截图。

因此,一个实用决策顺序是:先确认是否需要递归,再确认条件是否只有名称,最后补上普通文件判断和异常策略。这样可以避免用复杂过滤器解决一个简单的后缀匹配,也能避免把非递归 API 当成全盘搜索。

相关问题

DirectoryStream glob 会递归子目录吗?

不会。这个重载面向传入目录的直接目录项;需要递归时应选择递归遍历 API,并单独组织匹配条件。

glob 能判断一个路径一定是文件吗?

不能。它主要匹配目录项名称;如果必须排除目录,应在得到 Path 后调用 Files.isRegularFile 或使用自定义过滤器。

为什么迭代时不是直接抛 IOException?

Iterator 的接口方法不能直接声明受检 I/O 异常,所以目录迭代阶段的 I/O 问题可能包装成 DirectoryIteratorException。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>