8

I am using Java 8 Files.walk(..) to count .mp3 files contained inside a folder and all the folders inside it. In other words, I am visiting all the levels of the file tree.

When I get java.nio.file.AccessDeniedException the Stream closes, I don't want this behavior. I need it to ignore or print the exception and continue counting files. Below is the code I use :) :

   /**
     * Count files in a directory (including files in all sub
     * directories)
     * 
     * @param directory
     *        the directory to start in
     * @return the total number of files
     */
    public int countFiles(File dir) {
        if (dir.exists())
            try (Stream<Path> paths = Files.walk(Paths.get(dir.getPath()), FileVisitOption.FOLLOW_LINKS)) {
                return (int) paths.filter(path -> {

                    // i am using something different here but i changed
                    // it just for the purpose of StackOverFlow question                                
                    return path.toString().contains(".mp3");

                }).count();
            } catch (IOException ex) {
                //Main.logger.log(Level.WARNING, "", ex);
                ex.printStackTrace();
            }

        return 0;
    }

StackTrace of error:

java.io.UncheckedIOException: java.nio.file.AccessDeniedException: C:\$Recycle.B
in\S-1-5-18
    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.jav
a:1801)
    at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
    at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
    at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.util.stream.LongPipeline.reduce(LongPipeline.java:438)
    at java.util.stream.LongPipeline.sum(LongPipeline.java:396)
    at java.util.stream.ReferencePipeline.count(ReferencePipeline.java:526)
    at smartcontroller.SmartController$InputService$1.countFiles(SmartController.ja
va:2092)
...

Similar question , though not the same I need a Stream to be returned .

Working around access denied in a FileWalking Tree in Java7 .


ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
GOXR3PLUS
  • 6,877
  • 9
  • 44
  • 93
  • use the non-try-with-resources version in the duplicate you link to –  May 16 '17 at 16:42
  • @JarrodRoberson I need to get a `Stream` , so i can use Java8 methods . Can you post an answer about it :) ? – GOXR3PLUS May 16 '17 at 16:44
  • Your code doesn't compile, inside the try block there is some messy code (a return and a count() which refer to nothing). Please post something correct to let us help you correctly :) – Prim May 16 '17 at 16:51
  • Which line of your code produces the error? Does the error come from something you're doing inside the `filter`? Or is it coming from the `Files.walk`? – 4castle May 16 '17 at 16:54
  • @Prim My mistake though editing i fixed it :) – GOXR3PLUS May 16 '17 at 16:55
  • @4castle My mistake though editing i fixed it :) The error is coming from `File.walk(..)` – GOXR3PLUS May 16 '17 at 16:55
  • 2
    @JarrodRoberson Hello Jarrod :) , i read the link of the duplicate you posted . Though it is not what i am searching for . The exception comes from `try (Stream paths = Files.walk(Paths.get(dir.getPath()), FileVisitOption.FOLLOW_LINKS))` , so whatever i do it will throw the exception . **I need internally to fix Files.walk(...)** . So it might be duplicate but not the kind of duplicate you marked it for ... Any idea you have you can post it as answer . – GOXR3PLUS May 16 '17 at 17:07
  • unless you are going to recompile the JRE you can not do what you want, the duplicate has a pretty comprehensive list of all the valid alternatives for working with streams that throw checked exceptions. –  May 16 '17 at 17:10
  • @JarrodRoberson Hello Jarrod . Can you open the question so i add my own answer :) ? So future readers can improve it , actually it needs improvement . – GOXR3PLUS May 16 '17 at 19:35
  • 1
    I agree that this has little to do with the linked duplicate. Reopening. – shmosel May 17 '17 at 22:35
  • @shmosel I thank you [infinitely](https://www.youtube.com/watch?v=tapbVpw_9F8) ! :) I added an answer , though not the best in my opinion . – GOXR3PLUS May 17 '17 at 22:38
  • @shmosel Yep that's the correct duplicate link . – GOXR3PLUS May 17 '17 at 22:51

1 Answers1

5

Answer

Here is a temporary solution , which can be improved to use Java 8 Streams and Lambdas.

int[] count = {0};
try {
    Files.walkFileTree(
            Paths.get(dir.getPath()), 
            new HashSet<FileVisitOption>(Arrays.asList(FileVisitOption.FOLLOW_LINKS)),
            Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 
                        throws IOException {
                    System.out.printf("Visiting file %s\n", file);
                    ++count[0];
                    return FileVisitResult.CONTINUE;
                }
                
                @Override
                public FileVisitResult visitFileFailed(Path file, IOException e) 
                        throws IOException {
                    System.err.printf("Visiting failed for %s\n", file);
                    return FileVisitResult.SKIP_SUBTREE;
                }
                
                @Override
                public FileVisitResult preVisitDirectory(Path dir,
                                                         BasicFileAttributes attrs) 
                        throws IOException {
                    System.out.printf("About to visit directory %s\n", dir);
                    return FileVisitResult.CONTINUE;
                }
            });
} catch (IOException e) {
    // handle exception
}
Community
  • 1
  • 1
GOXR3PLUS
  • 6,877
  • 9
  • 44
  • 93
  • Hello I see this list all files, nice, How to do for get size of directory, each first directory? And Only List first level? – Fernando Pie Apr 24 '19 at 01:49
  • There is an option called max depth :) https://www.logicbig.com/how-to/code-snippets/jcode-java-io-files-walkfiletree.html , you need to modify the code a little bit though to fit exactly your needs . You can make a question on StackOverFlow and send me the link so i can answer . – GOXR3PLUS Apr 24 '19 at 08:33
  • Hello @GOXR3PLUS and Thanks for you interest. https://stackoverflow.com/questions/55830126/visiting-first-level-of-directory-and-get-size-of-each-directory-java?noredirect=1#comment98324956_55830126 – Fernando Pie Apr 24 '19 at 12:37
  • Just to clarify that there is no point returning `SKIP_SUBTREE` from `visitFileFailed()`. It only has meaning when returned from `preVisitDirectory()` – ne1410s Nov 27 '19 at 15:31
  • So basically `FileVisitResult.SKIP_SUBTREE` doesn't work if a folder can't be visited and we should put `FileVisitResult.SKIP_SUBTREE` on `preVisitDirectory` ? – GOXR3PLUS Nov 27 '19 at 15:45
  • 1
    Yes - well the second half at least :) It's just that the ability to skip a directory can **only** be decided in `preVisitDirectory()`. Trying to skip a directory from a *file* failure behaves the same as continuing. – ne1410s Nov 27 '19 at 16:08
  • Thank you i will have a look on that , the current code strangely works and i am confused :) – GOXR3PLUS Nov 28 '19 at 09:18
  • @ne1410s Now i am rethinking what you said before , how to know if we should `SKIP_SUBTREE` in `preVisitDirectory` , i don't find your comment valid . – GOXR3PLUS Feb 03 '20 at 12:17
  • Instead of creating an array of FileVisitOptions, converting it to list and then to a set, you could write it much simpler like this: `EnumSet.of(FileVisitOption.FOLLOW_LINKS)` – Hoov Apr 25 '22 at 11:46