Files.walkFileTree遍历目录文件的入门学习

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

参数1:路径 参数2:FileVisitor对象
public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)

遍历行为控制器FileVisitor
接口java.nio.file.FileVisitor包含四个方法,涉及到遍历过程中的几个重要的步骤节点。一般实际中使用SimpleFileVisitor简化操作。

public interface FileVisitor<T> {
   
   

    FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
        throws IOException;

    FileVisitResult visitFile(T file, BasicFileAttributes attrs)
        throws IOException;

    FileVisitResult visitFileFailed(T file, IOException exc)
        throws IOException;

    FileVisitResult 
<think> 我们参考引用内容[1][2][3][4]来解答用户的问题: 用户问题:Files.walkFileTree()方法是否会遍历文件?如何仅遍历目录? 根据引用内容: 引用[1]:"Files类提供了walkFileTree()方法来灵活遍历文件。" 引用[2]:"表示从start代表的节点开始遍历文件系统;" 引用[3]:"walkFileTree()包含用于递归遍历目录树的方法,方法参数接收一个Path对象和一个FileVisitor对象,Path对象指向需要遍历目录,FileVisitor在遍历的时候调用。" 引用[4]中的示例代码同时实现了对目录(preVisitDirectory)和文件(visitFile)的处理。 因此,Files.walkFileTree()方法默认会同时遍历目录文件。因为FileVisitor接口中定义了四个方法,其中: - preVisitDirectory: 在访问目录之前调用 - visitFile: 在访问文件时调用 - visitFileFailed: 访问文件失败时调用 - postVisitDirectory: 在访问目录之后调用 所以,该方法会遍历目录树中的所有节点,包括目录文件。 但是,用户希望仅遍历目录(即只处理目录,不处理文件),我们可以通过以下方式实现: 1. 在自定义的FileVisitor中,我们只需实现preVisitDirectory(或postVisitDirectory)方法来处理目录。 2. 对于visitFile方法,我们直接返回CONTINUE,表示继续遍历,但不做任何处理(或甚至不重写该方法,因为SimpleFileVisitor中默认的实现就是返回CONTINUE)。 3. 但是,为了效率,如果我们明确知道不需要处理文件,我们可以在visitFile方法中直接跳过,这样不会执行任何文件处理逻辑。 然而,即使我们不处理文件遍历过程仍然会访问文件(即visitFile方法会被调用),这可能会带来一定的性能开销(尤其是文件数量巨大时)。 有没有办法完全不访问文件?答案是没有。因为walkFileTree的设计就是遍历整个目录树,包括文件目录。但是我们可以通过两种方式优化: 方法一:在visitFile方法中不做任何操作,仅返回FileVisitResult.CONTINUE。这样虽然方法会被调用,但开销很小。 方法二:通过设置FileVisitOption,但标准API中没有提供跳过文件的选项。 因此,我们只能接受在遍历目录树时,文件也会被访问的事实,但我们可以忽略它们。 示例:仅处理目录遍历 我们只需要在preVisitDirectory(或postVisitDirectory)中处理目录,并在visitFile中快速返回CONTINUE即可。 代码示例: ```java import java.nio.file.*; import java.nio.file.attribute.*; import java.io.IOException; public class DirectoryOnlyTraversal { public static void main(String[] args) throws IOException { Path start = Paths.get("F:\\TestFile"); Files.walkFileTree(start, new SimpleFileVisitor<Path>() { // 处理目录:在进入目录前调用 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { System.out.println("目录: " + dir); // 这里可以添加你的目录处理逻辑 return FileVisitResult.CONTINUE; } // 处理文件:这里我们只是简单地跳过(不做任何操作) @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { // 不处理文件,直接跳过 return FileVisitResult.CONTINUE; } // 可选:处理文件读取失败的情况 @Override public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { // 可以记录错误,但继续遍历 System.err.println("访问文件失败: " + file); return FileVisitResult.CONTINUE; } }); } } ``` 这样,虽然visitFile方法被调用了,但我们没有做任何操作,所以效果上我们只处理了目录。 性能考虑:在文件数量非常大的情况下,即使visitFile方法不做任何操作,调用方法本身的开销也会累计。但是,这个开销很小。如果目录树中有海量文件,这个开销可能变得显著。目前,Java API没有提供跳过文件的选项,所以这是唯一的方法。 另外,我们可以在preVisitDirectory中通过返回SKIP_SUBTREE来跳过某些目录遍历(包括该目录下的所有文件和子目录),这可以用于减少不必要的访问。 总结: - walkFileTree遍历文件目录。 - 通过忽略visitFile方法(仅返回CONTINUE),我们可以实现只处理目录的逻辑。 - 无法完全避免访问文件(即visitFile方法会被调用),但我们可以选择不做任何操作。 注意:如果目录树中文件数量巨大,遍历可能会比较慢,因为每个文件都会触发一次visitFile调用。 另外,如果用户希望跳过某些目录(例如隐藏目录),可以在preVisitDirectory中判断并返回FileVisitResult.SKIP_SUBTREE。 相关问题: §§相关问题§§ 1. 如何使用walkFileTree方法跳过隐藏目录? 2.遍历大型文件系统时,如何优化walkFileTree的性能? 3. 如何利用walkFileTree统计目录大小? </think> ### Files.walkFileTree() 方法的行为解析 #### 1️⃣ **是否会遍历文件?** 是的,`Files.walkFileTree()` **默认会同时遍历目录文件**。这是由其回调机制决定的: - 当访问**目录**时,会触发 `preVisitDirectory()` 方法 [^3] - 当访问**文件**时,会触发 `visitFile()` 方法 [^3][^4] 引用[4]的代码示例明确展示了这一点: ```java Files.walkFileTree(Paths.get(path),new SimpleFileVisitor<Path>(){ @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { System.out.println("正在操作的目录:"+dir); // 目录回调 } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { System.out.println("当前正在处理的文件:"+file); // 文件回调 } }); ``` #### 2️⃣ **如何仅遍历目录(跳过文件)** 通过自定义 `FileVisitor` 实现,**只需重写目录处理方法,忽略文件处理方法**: ```java Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() { // 仅处理目录 @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { System.out.println("找到目录: " + dir); return FileVisitResult.CONTINUE; } // 跳过文件处理 (关键) @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { return FileVisitResult.CONTINUE; // 直接跳过不处理 } }); ``` #### 3️⃣ 性能优化技巧 1. **终止子树遍历**: ```java @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { if (dir.toString().contains("temp")) { return FileVisitResult.SKIP_SUBTREE; // 跳过整个子树 } // ...处理目录 } ``` 2. **过滤系统文件**: ```java @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { if (Files.isHidden(dir)) { return FileVisitResult.SKIP_SUBTREE; // 跳过隐藏目录 } // ...处理目录 } ``` 3. **深度控制**(Java 8+): ```java // 仅遍历3层深度 Files.walk(startPath, 3) .filter(Files::isDirectory) .forEach(System.out::println); ``` ### 执行原理说明 $$ \begin{array}{c} \text{遍历起始} \\ \downarrow \\ \text{preVisitDirectory()} \rightarrow \text{目录处理} \\ \downarrow \\ \begin{cases} \text{是文件?} \rightarrow \text{visitFile()} \\ \text{是子目录?} \rightarrow \text{递归进入} \end{cases} \\ \downarrow \\ \text{postVisitDirectory()} \\ \end{array} $$ 该方法采用**深度优先遍历算法**,通过控制回调返回值(`CONTINUE`/`SKIP_SUBTREE`/`TERMINATE`)实现精准控制[^2][^3]。 ### 目录专用遍历推荐(Java 8+) ```java try (Stream<Path> dirStream = Files.list(startPath)) { dirStream.filter(Files::isDirectory) .forEach(dir -> System.out.println("纯目录: " + dir)); } ``` 此方法**天然跳过文件**,但仅处理单层目录(非递归)。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值