假设我有以下目录结构
/root/dir
/root/dir/file1.txt
/root/dir/subdir
/root/dir/subdir/file2.txt假设我将使用以下访问者:
class MyFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
throws IOException {
if(Files.isDirectory(file)) {
throw new IllegalStateException("WAT!? Visiting directory: "+file.toAbsolutePath().toString());
}
System.out.println("Visiting file: "+file.toAbsolutePath().toString());
return super.visitFile(file, attrs);
}如果我们使用walkFileTree的简单重载:
Files.walkFileTree(Paths.get("/root/dir"), new MyFileVisitor()); 一切按计划进行,我们看到以下输出:
Visiting file: /root/dir/file1.txt
Visiting file: /root/dir/subdir/file2.txt但是当我们尝试设置最大深度时,事情就开始崩溃了:
Files.walkFileTree(Paths.get("/root/dir"), EnumSet.noneOf(FileVisitOption.class), 1, new MyFileVisitor());输出:
Visiting file: /root/dir/file1.txt
java.lang.IllegalStateException: WAT!? Visting directory: /root/dir/subdir我很确定这是一个bug,但我想首先问社区:我是否遗漏了什么,这实际上是预期的行为吗?谢谢你的确认!
详细信息:
java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)发布于 2014-01-02 20:19:59
我玩了一下你的代码,并添加了几行代码:
/*
* (non-Javadoc)
*
* @see java.nio.file.SimpleFileVisitor#preVisitDirectory(java.lang.Object,
* java.nio.file.attribute.BasicFileAttributes)
*/
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
System.out.println(Thread.currentThread().getStackTrace()[1] + " "
+ dir);
return super.preVisitDirectory(dir, attrs);
}
/*
* (non-Javadoc)
*
* @see java.nio.file.SimpleFileVisitor#postVisitDirectory(java.lang.Object,
* java.io.IOException)
*/
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc)
throws IOException {
System.out.println(Thread.currentThread().getStackTrace()[1] + " "
+ dir);
return super.postVisitDirectory(dir, exc);
}
/*
* (non-Javadoc)
*
* @see java.nio.file.SimpleFileVisitor#visitFileFailed(java.lang.Object,
* java.io.IOException)
*/
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc)
throws IOException {
System.out.println(Thread.currentThread().getStackTrace()[1] + " "
+ file);
return super.visitFileFailed(file, exc);
}只是没脑子看看到底怎么回事。
你所说的bug发生在这里,java.nio.file.FileTreeWalker:134
// at maximum depth or file is not a directory
if (depth >= maxDepth || !attrs.isDirectory()) {
return visitor.visitFile(file, attrs);
}最后,我的想法是:
1.:subdir是深度1的一部分
2.:如果没有用于最深目录的visitFile,您甚至都不会认识到它们在那里。
所以我认为这是正规行为。
顺便说一句,您可以在覆盖以下内容时使用attrs:
@Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs) throws IOException {
if (attrs.isDirectory()) {
throw new IllegalStateException("WAT!? Visiting directory: "
+ file.toAbsolutePath().toString());
}
System.out
.println("Visiting file: " + file.toAbsolutePath().toString());
return super.visitFile(file, attrs);
}发布于 2018-12-14 11:18:28
我真的相信
java.nio.file.Files#walkFileTree(java.nio.file.Path, java.util.Set, int, java.nio.file.FileVisitor)
破坏了java.nio.file.FileVisitor接口的契约。
简单地说,visitFile方法是在目录上调用的,如果它们恰好在所提供的深度级别上的话,它们也是。
如果您阅读接口java.nio.file.FileVisitor#visitFile的文档,这实际上是没有意义的,它明确指出:
为目录中的文件调用。
示例:
给定以下文件系统结构:
───start_dir
│ file1.txt
│
├───dir1
│ file11.txt
│
└───dir2
└───dir21
file211.txt调用walkFileTree按预期在足够大的深度中工作
Files.walkFileTree(Paths.get("start_dir"),
EnumSet.noneOf(FileVisitOption.class),
1000,
new MyFileVisitor());生成与接口一致的下列调用:
Previsit dir: start_dir
Previsit dir: start_dir\dir1
Visit file: start_dir\dir1\file11.txt
Postvisit dir: start_dir\dir1
Previsit dir: start_dir\dir2
Previsit dir: start_dir\dir2\dir21
Visit file: start_dir\dir2\dir21\file211.txt
Postvisit dir: start_dir\dir2\dir21
Postvisit dir: start_dir\dir2
Visit file: start_dir\file1.txt
Postvisit dir: start_dir用walkFileTree深度1调用
Files.walkFileTree(Paths.get("start_dir"),
EnumSet.noneOf(FileVisitOption.class),
1,
new MyFileVisitor());生成以下调用,其中除文件外,还在第一级目录上调用visitFile:
Previsit dir: start_dir
Visit file: start_dir\dir1
Visit file: start_dir\dir2
Visit file: start_dir\file1.txt
Postvisit dir: start_dir用walkFileTree深度2调用
Files.walkFileTree(Paths.get("start_dir"),
EnumSet.noneOf(FileVisitOption.class),
2,
new MyFileVisitor());生成以下调用,其中visitFile是,而不是在第一级目录上调用的,而是在第二级目录上调用的:
Previsit dir: start_dir
Previsit dir: start_dir\dir1
Visit file: start_dir\dir1\file11.txt
Postvisit dir: start_dir\dir1
Previsit dir: start_dir\dir2
Visit file: start_dir\dir2\dir21
Postvisit dir: start_dir\dir2
Visit file: start_dir\file1.txt
Postvisit dir: start_dir发布于 2019-10-27 19:45:41
此行为是在文件文档::演练文件树中指定的,因此它是有意的,而不是bug:
对在visitFile中遇到的所有文件(包括目录)调用maxDepth方法。
为了防止在目录上调用visitFile,目录在整个java.nio.file类的文档中被隐式调用。例如,Files::walkFileTree的文档本身说,“该方法遍历根植于给定起始文件的文件树”,并且“启动文件”(当然)可能是一个目录。
还请注意,也可以在目录上调用visitFileFailed,如文档中所解释的那样:
如果该文件是一个目录,并且无法打开该目录,则调用visitFileFailed方法时会出现I/O异常。
Franz展示了发生这种行为的代码,我同意他为什么认为这是故意的:“如果没有最深目录的visitFile,您甚至都不会认识到它们在那里。”如果只需要常规文件(或符号链接),我也同意使用attrs参数检查文件类型。
https://stackoverflow.com/questions/20676146
复制相似问题