Java Glob根目录匹配无结果问题及代码优化咨询
问题1:为什么glob:*.*没有返回结果?
这是因为PathMatcher默认是匹配完整的路径字符串,而不是仅匹配文件名。当你遍历文件时,path参数是完整的绝对路径(比如C:/Users/Krzysiek/Desktop/document.pdf),而glob:*.*这个模式只会匹配形如file.ext的短路径,显然和完整的绝对路径不匹配,所以没有文件被选中。
要解决这个问题,有两种实用方案:
方案A:匹配路径的文件名部分
修改visitFile方法的判断逻辑,让PathMatcher只校验文件的名称,而非整个路径:
@Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { // 仅匹配文件名部分 if (pathMatcher.matches(path.getFileName())) { paths.add(path); System.out.println(path); } return FileVisitResult.CONTINUE; }
如果只想匹配起始目录下的*.*文件,还可以额外判断路径的父目录是否等于起始目录:
Path baseDir = Paths.get(location); // 仅匹配起始目录下的带点文件名文件 if (path.getParent().equals(baseDir) && pathMatcher.matches(path.getFileName())) { paths.add(path); System.out.println(path); }
方案B:基于相对路径匹配
把完整路径转换成相对于起始目录的相对路径,再进行匹配,这样glob模式的逻辑会更符合直觉:
Path baseDir = Paths.get(location); // 在visitFile中转换为相对路径 Path relativePath = baseDir.relativize(path); if (pathMatcher.matches(relativePath)) { paths.add(path); System.out.println(path); }
这时glob:*.*会匹配起始目录下的所有带点文件名的文件,glob:**/*.*会匹配所有子目录中的对应文件,完全符合你的预期。
问题2:应该返回集合还是用静态属性?
强烈建议在match方法内部创建List并返回它,而非使用静态类属性,原因如下:
- 线程安全与数据一致性:静态属性是类级别的,单线程下多次调用
match会累积之前的结果,多线程环境下更是会出现数据混乱,完全不符合方法的预期行为。 - 封装性与代码可读性:静态属性暴露了类的内部状态,不符合面向对象的封装原则。直接返回集合的方式更清晰,调用者无需关心类内部的存储逻辑,也避免了意外修改静态集合的风险。
修改后的FileGlobNIO类示例:
import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.List; public class FileGlobNIO { // 移除静态属性,改为方法内创建集合 public static List<Path> match(String glob, String location) throws IOException { final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob); final List<Path> paths = new ArrayList<>(); Path baseDir = Paths.get(location); Files.walkFileTree(baseDir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { Path relativePath = baseDir.relativize(path); if (pathMatcher.matches(relativePath)) { paths.add(path); System.out.println(path); // debug } return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { return FileVisitResult.CONTINUE; } }); return paths; } }
对应的Main类调用方式:
import java.io.IOException; import java.util.List; import java.nio.file.Path; public class Main { public static void main(String[] args) { String glob = "glob:*.*"; // 现在可正确匹配起始目录下的带点文件 String path = "C:/Users/Krzysiek/Desktop/"; try { List<Path> matchedPaths = FileGlobNIO.match(glob, path); System.out.println(matchedPaths.size()); } catch (IOException e) { throw new RuntimeException(e); } } }
这样修改后的代码更健壮、可维护,完全符合Java的最佳实践。
内容的提问来源于stack exchange,提问作者Krzysiek127
相关产品推荐
相关产品推荐

