英文:
FileVisitor not behaving as expected
问题
我一直在尝试使用实现了FileVisitor
接口的类,该类在preVisitDirectory
中简单地复制目录,在postVisitDirectory
中移动文件并删除目录。这在没有任何问题的情况下运行。
问题出在我尝试实现一个条件语句时:if(Files.list(dir).findAny().isEmpty())
除了最浅层的子目录外,其余的子目录仍然存在于原始目录中。目标目录被完全正确地填充。没有抛出任何错误。
如果我在条件语句的流中使用skip(1)
,会抛出DirectoryNotEmptyException
异常,在删除行上会出现异常。功能是不正确的,即使我没有使用skip
,结果与使用条件语句时一样。
如果我使用Files.list(dir).forEach(System.out::println);
进行打印输出,功能是不正确的,并且会再次在删除行上抛出异常。
另一个人认为功能不如预期,是因为这个:
System.out.println(dir + " : ");
Files.list(dir).forEach(System.out::println);
输出:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder\TriplyNestedFolder:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder\TriplyNestedFolder
> E:\EncrypterTest\TopSecret\NestedFolder :
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder
其中TriplyNestedFolder是目录中最深的文件夹。请记住,当代码完成时,TriplyNestedFolder将被删除。如果我不检查它们是否为空,其他两个文件夹也会被删除。
因此,总结起来似乎是:
- 首先访问最深的目录(预期行为),但尽管在其上调用了
.delete
,它仍然存在于其父目录中,以便进行删除。 - 在代码完成后被删除
- 所有父目录也都被删除,没有抛出异常
- 添加如上所示的条件语句会导致除最深的目录外的所有副本保留
- 在文件流中添加
.skip(1)
会导致来自第4点的功能,但会产生DirectoryNotEmptyException
异常 - 添加打印输出会导致与第5点相同的功能和异常
- 无论目录中是否有文件,行为都完全相同
我希望对于这里的某个人来说,这将是一些明显的事情,但是我束手无策。提前感谢您提供的任何帮助。如果您需要更多的信息/代码,请随时提问。
英文:
I have been trying to use a class that implements FileVisitor
and simply copies a directory in preVisitDirectory
, moves the files, and deletes the directory in `postVisitDirectory. This works without any problems.
The problem occurs when I try to implement a conditional: if(Files.list(dir).findAny().isEmpty())
All but the shallowest subdirectories persist in the original directory. The target directory is filled out 100% correctly. No error is thrown.
If I use skip(1)
in the stream of the conditional, a DirectoryNotEmptyException is thrown. *on the delete line.*Functionality is incorrect, i.e., the same as if I used the conditional without skip
.
If I do a printout with Files.list(dir).forEach(System.out::println);
, functionality is incorrect and the exception is thrown, again on the delete line
Another human thinks functionality was not as intended because this:
'System.out.println(dir + " : ");
Files.list(dir).forEach(System.out::println);'
Outputs:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder\TriplyNestedFolder:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder:
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder\TriplyNestedFolder
> E:\EncrypterTest\TopSecret\NestedFolder :
> E:\EncrypterTest\TopSecret\NestedFolder\DoublyNestedFolder
Where TriplyNestedFolder is the deepest folder in the directory. Remember, TriplyNestedFolder is being deleted when the code is complete. So are the other 2 if I don't check if they are empty.
So to recap it seems like:
- The deepest directory is being accessed first (as expected), but despite
.delete
being called on it, it still exists for the purpose of the.delete
in it's parent directory. - It is deleted after code completes
- Parent directories are all deleted as well with no exception thrown
- Adding a conditional as shown above causes copies of all but the deepest directory to remain
- Adding a
.skip(1)
in the files stream causes functionality from #4, but produces DirectoryNotEmptyException - Adding a printout causes the same functionality and exception from #5
- Exact same behavior occurs with or without files in the directories
I'm hoping this will be something obvious to someone here, but I'm at a loss. Thanks in advance for any help. If you need any more information/code please ask.
答案1
得分: 0
Javadoc Files.list(Path dir)
的说明如下:
> 返回一个惰性地填充的 Stream,其中的元素是目录中的条目。[...]
>
> [...]
>
> 返回的流封装了一个 DirectoryStream
。如果需要及时释放文件系统资源,应使用try-with-resources结构,以确保在完成流操作后调用流的 close
方法。
>
> [...]
这意味着返回的流保持着一个打开的操作系统目录句柄,这在Windows上可能会阻止删除目录。
Files.list()
的正确使用方式如下:
boolean isEmpty;
try (Stream<Path> pathStream = Files.list(dir)) {
isEmpty = pathStream.findAny().isEmpty();
}
if (isEmpty) {
// 我们现在可以删除目录,因为我们已经释放了流使用的资源,即我们已经关闭了句柄
}
英文:
Javadoc of Files.list(Path dir)
says:
> Return a lazily populated Stream, the elements of which are the entries in the directory. [...]
>
> [...]
>
> The returned stream encapsulates a DirectoryStream
. If timely disposal of file system resources is required, the try-with-resources construct should be used to ensure that the stream's close
method is invoked after the stream operations are completed.
>
> [...]
This means that the returned stream keeps an open OS directory handle, which on Windows may prevent the directory from being deleted.
Correct use of Files.list()
is:
boolean isEmpty;
try (Stream<Path> pathStream = Files.list(dir)) {
isEmpty = pathStream.findAny().isEmpty();
}
if (isEmpty) {
// We can delete the directory here, since we've now released
// the resources used by the stream, i.e. we've closed the handle
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论