Reputation: 2105
I'm a newbie of java8 streaming word, but I want to understand that. After making some simple stuff, I went deeper, so I like to list all the files in a folder. I got the idea from here.
Files.walk(start)
.filter(Files::isRegularFile)
.forEach(System.out::println);
It works well, but I ran that a folder, where some spec file are located, and throws AccessDeniedException
. I made some search, and I know its not a simple problem. I try to handle the exception like this:
private static Predicate<Path> fillAccessDenied() {
return p -> {
try {
if(Files.isRegularFile(p)) {
return true;
} else {
return false;
}
} catch (UncheckedIOException e) {
e.printStackTrace();
return false;
}
};
}
//....
Files.walk(start)
.filter(Utils.fillAccessDenied())
.forEach(System.out::println);
But the problem remains, and I don't understand why. Can somebody give me some clue what is the problem here?
Thanks in advance!
EDIT:
I took the system out between a try catch, but the problem remains.
public static void println(Object x) {
try {
String s = String.valueOf(x);
System.out.println(s);
} catch (UncheckedIOException e) {
e.printStackTrace();
}
}
//...
Files.walk(start)
.filter(Utils.fillAccessDenied())
.forEach(Utils::println);
My input path "/" and I run it on linux. Does it cause this problem?
stacktrace:
java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /etc/sysconfig/network/providers
at java.nio.file.FileTreeIterator.fetchNextIfNeeded(FileTreeIterator.java:88)
at java.nio.file.FileTreeIterator.hasNext(FileTreeIterator.java:104)
at java.util.Iterator.forEachRemaining(Iterator.java:115)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at hu.gergelylakatos.jbackupper.JBackupper.main(JBackupper.java:45)
Caused by: java.nio.file.AccessDeniedException: /etc/sysconfig/network/providers
at sun.nio.fs.UnixException.translateToIOException(UnixException.java:84)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream(UnixFileSystemProvider.java:427)
at java.nio.file.Files.newDirectoryStream(Files.java:457)
at java.nio.file.FileTreeWalker.visit(FileTreeWalker.java:300)
at java.nio.file.FileTreeWalker.next(FileTreeWalker.java:372)
at java.nio.file.FileTreeIterator.fetchNextIfNeeded(FileTreeIterator.java:95)
... 10 more
Upvotes: 2
Views: 2342
Reputation: 298153
You can not catch the exception at Files.isRegularFile
when it isn’t thrown at this place. Since the exception is thrown inside the code implementing iteration logic of Files.walk
, you can only catch it at the forEach
method, when it has already terminated the entire operation.
You may implement the iteration logic yourself to have more control. E.g.
public static Stream<Path> traverse(Path p, BiConsumer<Path,IOException> handler) {
if(Files.isDirectory(p)) try {
return Stream.concat(Stream.of(p),
Files.list(p).flatMap(sub -> traverse(sub, handler)));
} catch(IOException ex) {
handler.accept(p,ex);
}
return Stream.of(p);
}
which you may use like
traverse(start, (p,ex) -> System.err.println(p+": "+ex))
.filter(Files::isRegularFile)
.forEach(System.out::println);
to print the exception and continue, or
traverse(start, (p,ex) -> { throw new UncheckedIOException(ex); })
.filter(Files::isRegularFile)
.forEach(System.out::println);
to bail out like Files.walk
.
When you know that you are interested in regular files only, you can create a specialized method like
public static Stream<Path> traverseLeafs(Path p, BiConsumer<Path,IOException> handler) {
if(Files.isDirectory(p)) try {
return Files.list(p).flatMap(sub -> traverseLeafs(sub, handler));
} catch(IOException ex) {
handler.accept(p,ex);
return Stream.empty();
}
return Stream.of(p);
}
which excludes directories right at the source. You may still use filter(Files::isRegularFile)
though, to exclude special files which are neither directory nor regular file.
You may also use Files.isDirectory(p) && Files.isReadable(p)
as condition here, to prevent the AccessDeniedException
from occurring, at least as long as the access flags do not change between Files.isReadable(p)
and Files.list(p)
.
Upvotes: 4
Reputation: 1590
I believe you need to change your filter. Checking if the file isRegular
, doesn't mean you won't get the AccessException
.
Ensure you're filtering out folders.
private static Predicate<Path> fillAccessDenied() {
return p -> {
try {
if(Files.isReadable(p) && !Files.isDirectory(p)) {
return true;
} else {
return false;
}
} catch (UncheckedIOException e) {
e.printStackTrace();
return false;
}
};
}
Upvotes: 0