[JAVA] 使用Files.walkFileTree遍历目录文件

2002 0
王子 2022-11-9 09:33:37 | 显示全部楼层 |阅读模式
目录

    1.Files.walkFileTree的原理介绍2.遍历行为控制器FileVisitor3.遍历行为结果 FileVisitResult4.查找指定文件5.使用PathMatcher
      5.1全局规则glob5.2正则规则regex
    6.查找指定文件7.遍历单层目录8.复制文件到新目录9.文件和流的复制10.Path与File的转换

java.nio.file.Files.walkFileTree是JDK7新增的静态工具方法。

1.Files.walkFileTree的原理介绍
  1. static Path walkFileTree(Path start, Set<FileVisitOption> options, int maxDepth, FileVisitor<? super Path> visitor) throws IOException;
  2. static Path walkFileTree(Path start, FileVisitor<? super Path> visitor) throws IOException;
复制代码
参数列表:
    java.nio.file.Path start 遍历的起始路径Set<java.nio.file.FileVisitOption> options 遍历选项int maxDepth 遍历深度java.nio.file.FileVisitor<? super Path> visitor 遍历过程中的行为控制器

2.遍历行为控制器FileVisitor

接口java.nio.file.FileVisitor包含四个方法,涉及到遍历过程中的几个重要的步骤节点。
一般实际中使用SimpleFileVisitor简化操作。
  1. public interface FileVisitor<T> {
  2.     FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
  3.         throws IOException;
  4.     FileVisitResult visitFile(T file, BasicFileAttributes attrs)
  5.         throws IOException;
  6.     FileVisitResult visitFileFailed(T file, IOException exc)
  7.         throws IOException;
  8.     FileVisitResult postVisitDirectory(T dir, IOException exc)
  9.         throws IOException;
  10. }
复制代码
    preVisitDirectory 访问一个目录,在进入之前调用。postVisitDirectory一个目录的所有节点都被访问后调用。遍历时跳过同级目录或有错误发生,Exception会传递给这个方法visitFile 文件被访问时被调用。该文件的文件属性被传递给这个方法visitFileFailed 当文件不能被访问时,此方法被调用。Exception被传递给这个方法。

3.遍历行为结果 FileVisitResult
  1. public enum FileVisitResult {
  2.     CONTINUE,
  3.     TERMINATE,
  4.     SKIP_SUBTREE,
  5.     SKIP_SIBLINGS;
  6. }
复制代码
    CONTINUE 继续遍历SKIP_SIBLINGS 继续遍历,但忽略当前节点的所有兄弟节点直接返回上一层继续遍历SKIP_SUBTREE 继续遍历,但是忽略子目录,但是子文件还是会访问TERMINATE 终止遍历

4.查找指定文件

使用java.nio.file.Path提供的startsWith、endsWith等方法,需要特别注意的是:匹配的是路径节点的完整内容,而不是字符串。
例如: /usr/web/bbf.jar
  1. Path path = Paths.get("/usr/web/bbf.jar");
  2. path.endsWith("bbf.jar"); // true
  3. path.endsWith(".jar");   // false
复制代码
5.使用PathMatcher
  1. @Test
  2. public void visitFile2() throws IOException {
  3.   // 查找java和txt文件
  4.   String glob = "glob:**/*.{java,txt}";
  5.   String path = "D:\\work_java\\bbf\\CORE";
  6.   final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
  7.   Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
  8.     @Override
  9.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
  10.         throws IOException {
  11.       if (pathMatcher.matches(file)) {
  12.         System.out.println(file);
  13.       }
  14.       return FileVisitResult.CONTINUE;
  15.     }
  16.   });
  17. }
复制代码
getPathMatcher方法的参数语法:规则:模式,其中规则支持两种模式glob和regex。

5.1全局规则glob

使用类似于正则表达式但语法更简单的模式,匹配路径的字符串。
    glob:*.java 匹配以java结尾的文件glob:. 匹配包含’.'的文件glob:*.{java,class} 匹配以java或class结尾的文件glob:foo.? 匹配以foo开头且一个字符扩展名的文件glob:/home// 在unix平台上匹配,例如/home/gus/data等glob:/home/** 在unix平台上匹配,例如/home/gus,/home/gus/dataglob:c:\\* 在windows平台上匹配,例如c:foo,c:bar,注意字符串转义
5.1.1规则说明
    * 匹配零个或多个字符与名称组件,不跨越目录** 匹配零个或多个字符与名称组件,跨越目录(含子目录)? 匹配一个字符的字符与名称组件\ 转义字符,例如{表示匹配左花括号[] 匹配方括号表达式中的范围,连字符(-)可指定范围。例如[ABC]匹配"A"、“B"和"C”;[a-z]匹配从"a"到"z";[abce-g]匹配"a"、“b”、“c”、“e”、“f”、“g”;[!..]匹配范围之外的字符与名称组件,例如[!a-c]匹配除"a"、“b”、"c"之外的任意字符{}匹配组中的任意子模式,多个子模式用","分隔,不能嵌套。

5.2正则规则regex

使用java.util.regex.Pattern支持的正则表达式。
5.2.1示例
获取指定扩展名的文件
以下测试用例,目的都是获取指定目录下的.properties和.html文件。
  1. /**
  2. * 递归遍历,字符串判断
  3. *
  4. * @throws IOException IO异常
  5. */
  6. @Test
  7. public void visitFile1() throws IOException {
  8.   String path = "D:\\work_java\\hty\\HTY_CORE";
  9.   Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
  10.     @Override
  11.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
  12.         throws IOException {
  13.       String pathStr = file.toString();
  14.       if (pathStr.endsWith("properties") || pathStr.endsWith("html")) {
  15.         System.out.println(file);
  16.       }
  17.       return FileVisitResult.CONTINUE;
  18.     }
  19.   });
  20. }
  21. /**
  22. * 递归遍历,glob模式
  23. *
  24. * @throws IOException IO异常
  25. */
  26. @Test
  27. public void visitFile2() throws IOException {
  28.   String glob = "glob:**/*.{properties,html}";
  29.   String path = "D:\\work_java\\hty\\HTY_CORE";
  30.   final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(glob);
  31.   Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
  32.     @Override
  33.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
  34.         throws IOException {
  35.       if (pathMatcher.matches(file)) {
  36.         System.out.println(file);
  37.       }
  38.       return FileVisitResult.CONTINUE;
  39.     }
  40.   });
  41. }
  42. /**
  43. * 递归遍历,正则模式
  44. *
  45. * @throws IOException IO异常
  46. */
  47. @Test
  48. public void visitFile3() throws IOException {
  49.   // (?i)忽略大小写,(?:)标记该匹配组不应被捕获
  50.   String reg = "regex:.*\\.(?i)(?:properties|html)";
  51.   String path = "D:\\work_java\\hty\\HTY_CORE";
  52.   final PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(reg);
  53.   Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
  54.     @Override
  55.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
  56.         throws IOException {
  57.       if (pathMatcher.matches(file)) {
  58.         System.out.println(file);
  59.       }
  60.       return FileVisitResult.CONTINUE;
  61.     }
  62.   });
  63. }
复制代码
6.查找指定文件
  1. /**
  2. * 查找指定文件
  3. *
  4. * @throws IOException IO异常
  5. */
  6. @Test
  7. public void visitFile() throws IOException {
  8.   String path = "D:\\work_java\\hty\\HTY_CORE\\src";
  9.   Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>() {
  10.     @Override
  11.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
  12.         throws IOException {
  13.       // 使用endsWith,必须是路径中的一段,而不是几个字符
  14.       if (file.endsWith("log.java")) {
  15.         System.out.println(file);
  16.         // 找到文件,终止操作
  17.         return FileVisitResult.TERMINATE;
  18.       }
  19.       return FileVisitResult.CONTINUE;
  20.     }
  21.   });
  22. }
复制代码
7.遍历单层目录

使用DirectoryStream会获取指定目录下的目录和文件。可以使用newDirectoryStream的第二个参数进行筛选,glob语法。
  1. /**
  2. * 遍历单层目录
  3. *
  4. * @throws IOException IO异常
  5. */
  6. @Test
  7. public void dir() throws IOException {
  8.   Path source = Paths.get("D:\\work_java\\hty\\HTY_CORE\\src\\main\\resources");
  9.   try (DirectoryStream<Path> stream = Files.newDirectoryStream(source, "*.xml")) {
  10.     Iterator<Path> ite = stream.iterator();
  11.     while (ite.hasNext()) {
  12.       Path pp = ite.next();
  13.       System.out.println(pp.getFileName());
  14.     }
  15.   }
  16. }
复制代码
8.复制文件到新目录
  1. /**
  2. * 递归复制
  3. *
  4. * @throws IOException IO异常
  5. */
  6. @Test
  7. public void copyAll() throws IOException {
  8.   Path source = Paths.get("D:\\work_java\\hty\\HTY_CORE\\src");
  9.   Path target = Paths.get("D:\\temp\\core");
  10.   // 源文件夹非目录
  11.   if (!Files.isDirectory(source)) {
  12.     throw new IllegalArgumentException("源文件夹错误");
  13.   }
  14.   // 源路径的层级数
  15.   int sourcePart = source.getNameCount();
  16.   Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
  17.     @Override
  18.     public FileVisitResult peVisitDirectory(Path dir, BasicFileAttributes attrs)
  19.         throws IOException {
  20.       // 在目标文件夹中创建dir对应的子文件夹
  21.       Path subDir;
  22.       if (dir.compareTo(source) == 0) {
  23.         subDir = target;
  24.       } else {
  25.         // 获取相对原路径的路径名,然后组合到target上
  26.         subDir = target.resolve(dir.subpath(sourcePart, dir.getNameCount()));
  27.       }
  28.       Files.createDirectories(subDir);
  29.       return FileVisitResult.CONTINUE;
  30.     }
  31.     @Override
  32.     public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
  33.       Files.copy(file, target.resolve(file.subpath(sourcePart, file.getNameCount())),
  34.           StandardCopyOption.REPLACE_EXISTING);
  35.       return FileVisitResult.CONTINUE;
  36.     }
  37.   });
  38.   System.out.println("复制完毕");
  39. }
复制代码
9.文件和流的复制
  1. /**
  2. * 流复制到文件
  3. *
  4. * @throws IOException IO异常
  5. */
  6. @Test
  7. public void copy1() throws IOException {
  8.   Path source = Paths.get("D:\\work_java\\hty\\HTY_CORE\\src\\main\\resources\\ehcache.xml");
  9.   Path target = Paths.get("D:\\temp\");
  10.   if (!Files.exists(target)) {
  11.     Files.createDirectories(target);
  12.   }
  13.   Path targetFile = target.resolve(source.getFileName());
  14.   try (InputStream fs = FileUtils.openInputStream(source.toFile())) {
  15.     Files.copy(fs, targetFile, StandardCopyOption.REPLACE_EXISTING);
  16.   }
  17. }
  18. /**
  19. * 文件复制到流
  20. *
  21. * @throws IOException IO异常
  22. */
  23. @Test
  24. public void copy2() throws IOException {
  25.   Path source = Paths.get("D:\\work_java\\hty\\HTY_CORE\\src\\main\\resources\\ehcache.xml");
  26.   Path target = Paths.get("D:\\temp\\core");
  27.   Path targetFile = target.resolve(source.getFileName());
  28.   if (!Files.exists(target)) {
  29.     Files.createDirectories(target);
  30.   }
  31.   try (OutputStream fs = FileUtils.openOutputStream(targetFile.toFile());
  32.       OutputStream out = new BufferedOutputStream(fs)) {
  33.     Files.copy(source, out);
  34.   }
  35. }
复制代码
10.Path与File的转换
  1. /**
  2. * Path与File的转换
  3. */
  4. @Test
  5. public void testPath() {
  6.         File file = new File("D:\\work_java\\hty\\HTY_CORE");
  7.         System.out.println(file.toURI());//file:/D:/work_java/hty/HTY_CORE
  8.         System.out.println(file.getAbsolutePath());//D:\work_java\hty\HTY_CORE
  9.         System.out.println(file.getName());//HTY_CORE
  10.         System.out.println("-------");
  11.         //File转换为Path
  12.         Path path = Paths.get(file.toURI());
  13.         System.out.println(path.toUri());//file:///D:/work_java/hty/HTY_CORE
  14.         System.out.println(path.toAbsolutePath());//D:\work_java\hty\HTY_CORE
  15.         System.out.println(path.getFileName());//HTY_CORE
  16.         System.out.println("-------");
  17.         //Path转换为File
  18.         File f = path.toFile();
  19.         System.out.println(f.getAbsolutePath());//D:\work_java\hty\HTY_CORE
  20. }
复制代码
以上为个人经验,希望能给大家一个参考,也希望大家多多支持中国红客联盟。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行