2

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
LakiGeri
  • 2,046
  • 6
  • 30
  • 56
  • You're still getting AccessDenied on files that are 'regular'. You could just add a method for printing, with a try catch and use that in your foreach – dustytrash Oct 12 '18 at 15:19
  • @dustytrash thx but did not fix the problem – LakiGeri Oct 12 '18 at 15:30
  • Change the catch to be a `AccessDeniedException` – dustytrash Oct 12 '18 at 15:32
  • My input path "/" and I run it on linux. Does it cause this problem? – LakiGeri Oct 12 '18 at 15:34
  • @dustytrash I got `Unreachable catch block for AccessDeniedException. This exception is never thrown from the try statement body` – LakiGeri Oct 12 '18 at 15:35
  • I think the exception occurs when you're working with a folder, not a file. I'll update my answer – dustytrash Oct 12 '18 at 15:43
  • 1
    Can you include the stack trace? You have to catch the exception where it is thrown. If `Files.isRegularFile` doesn’t throw that exception, there is no sense in trying to catch it there. – Holger Oct 12 '18 at 16:28
  • @Holger I included the trace. Thanks for the help. @dustytrash I extended with `&& !Files.isDirectory(p)` Now I made it the "old fashion way" so I try to catch my bug. :) – LakiGeri Oct 12 '18 at 16:51

2 Answers2

4

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).

Holger
  • 285,553
  • 42
  • 434
  • 765
0

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;
        }
    };
}
dustytrash
  • 1,568
  • 1
  • 10
  • 17
  • Thx for the answer, I changed the condition but the problem remains. I changed the system out as well, check the updated question. – LakiGeri Oct 12 '18 at 15:31