我正在尝试计算光盘上文件的大小。在Java的7本可以用做Files.walkFileTree如图我的答案在这里。
但是,如果我想使用java-8流来执行此操作,则它将适用于某些文件夹,但不适用于所有文件夹。
public static void main(String[] args) throws IOException { long size = Files.walk(Paths.get("c:/")).mapToLong(MyMain::count).sum(); System.out.println("size=" + size); } static long count(Path path) { try { return Files.size(path); } catch (IOException | UncheckedIOException e) { return 0; } }
上面的代码可以很好地用于路径,a:/files/但是c:/会抛出以下异常
a:/files/
c:/
Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException: c:\$Recycle.Bin\S-1-5-20 at java.nio.file.FileTreeIterator.fetchNextIfNeeded(Unknown Source) at java.nio.file.FileTreeIterator.hasNext(Unknown Source) at java.util.Iterator.forEachRemaining(Unknown Source) at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source) at java.util.stream.AbstractPipeline.copyInto(Unknown Source) at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(Unknown Source) at java.util.stream.AbstractPipeline.evaluate(Unknown Source) at java.util.stream.LongPipeline.reduce(Unknown Source) at java.util.stream.LongPipeline.sum(Unknown Source) at MyMain.main(MyMain.java:16)
我了解它的来源以及如何使用Files.walkFileTree API避免它。
但是如何使用Files.walk() API 避免这种异常?
不,无法避免此异常。
异常本身发生在的懒惰获取中Files.walk(),因此,为什么不及早看到它以及为什么没有办法规避它,请考虑以下代码:
Files.walk()
long size = Files.walk(Paths.get("C://")) .peek(System.out::println) .mapToLong(this::count) .sum();
在我的系统上,这将在我的计算机上打印:
C:\ C:\$Recycle.Bin Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException: C:\$Recycle.Bin\S-1-5-18
并且作为第三个文件的(主)线程上抛出的异常,该线程上的所有进一步执行都将停止。
我认为这是一个设计失败,因为从现在开始它Files.walk是绝对不可用的,因为您永远无法保证遍历目录时不会出现任何错误。
Files.walk
需要注意的重要一点是stacktrace包含sum()和reduce()操作,这是因为路径是延迟加载的,所以在的点reduce(),调用了大多数流机制(在stacktrace中可见),然后获取路径,此时UnCheckedIOException发生。
sum()
reduce()
UnCheckedIOException
如果让每个步行操作都在各自的线程上执行,则可能 会 被规避。但这不是您想做的事情。
另外,检查文件是否实际上可访问是 毫无价值的 (尽管在某种程度上很有用),因为您无法保证甚至在1毫秒后仍可读。
我相信它仍然可以修复,尽管我不知道它是如何FileVisitOption工作的。 当前有一个FileVisitOption.FOLLOW_LINKS,如果它基于每个文件运行,那么我怀疑FileVisitOption.IGNORE_ON_IOEXCEPTION也可以添加一个,但是我们无法在其中正确注入该功能。
FileVisitOption
FileVisitOption.FOLLOW_LINKS
FileVisitOption.IGNORE_ON_IOEXCEPTION