2

I know of the Apache Commons IO library for file directory processing in Java. However, List all files from a directory recursively with Java talks about native support in Java 7.

Does anyone have experience on how to recursively list/read files in a directory using Java 7?

Community
  • 1
  • 1
czchlong
  • 2,434
  • 10
  • 51
  • 65

2 Answers2

5

There's a tutorial on it. Basically you implement a Visitor which can then be called as directories are entered, exited, and files are encountered. There is support for determining if files are symbolic links, and options to follow the symbolic link (if you care to do so). A quick read on what Java Paths are might be useful, and the entire documentation starts here.

import static java.nio.file.FileVisitResult.*;

public static class PrintFiles
    extends SimpleFileVisitor<Path> {

    // Print information about
    // each type of file.
    @Override
    public FileVisitResult visitFile(Path file,
                                   BasicFileAttributes attr) {
        if (attr.isSymbolicLink()) {
            System.out.format("Symbolic link: %s ", file);
        } else if (attr.isRegularFile()) {
            System.out.format("Regular file: %s ", file);
        } else {
            System.out.format("Other: %s ", file);
        }
        System.out.println("(" + attr.size() + "bytes)");
        return CONTINUE;
    }

    // Print each directory visited.
    @Override
    public FileVisitResult postVisitDirectory(Path dir,
                                          IOException exc) {
        System.out.format("Directory: %s%n", dir);
        return CONTINUE;
    }

    // If there is some error accessing
    // the file, let the user know.
    // If you don't override this method
    // and an error occurs, an IOException 
    // is thrown.
    @Override
    public FileVisitResult visitFileFailed(Path file,
                                       IOException exc) {
        System.err.println(exc);
        return CONTINUE;
    }
}

A second example (from the Java implementation of find) that illustrates file walking could be easily modified to "match" all files.

/*
 * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import static java.nio.file.FileVisitResult.*;
import static java.nio.file.FileVisitOption.*;
import java.util.*;

/**
 * Sample code that finds files that
 * match the specified glob pattern.
 * For more information on what
 * constitutes a glob pattern, see
 * http://docs.oracle.com/javase/javatutorials/tutorial/essential/io/fileOps.html#glob
 *
 * The file or directories that match
 * the pattern are printed to
 * standard out.  The number of
 * matches is also printed.
 *
 * When executing this application,
 * you must put the glob pattern
 * in quotes, so the shell will not
 * expand any wild cards:
 *     java Find . -name "*.java"
 */

public class Find {

    /**
     * A {@code FileVisitor} that finds
     * all files that match the
     * specified pattern.
     */
    public static class Finder
        extends SimpleFileVisitor<Path> {

        private final PathMatcher matcher;
        private int numMatches = 0;

        Finder(String pattern) {
            matcher =
                FileSystems.getDefault()
                    .getPathMatcher("glob:" + pattern);
        }

        // Compares the glob pattern against
        // the file or directory name.
        void find(Path file) {
            Path name = file.getFileName();
            if (name != null && matcher.matches(name)) {
                numMatches++;
                System.out.println(file);
            }
        }

        // Prints the total number of
        // matches to standard out.
        void done() {
            System.out.println("Matched: "
                + numMatches);
        }

        // Invoke the pattern matching
        // method on each file.
        @Override
        public FileVisitResult
            visitFile(Path file,
                BasicFileAttributes attrs) {
            find(file);
            return CONTINUE;
        }

        // Invoke the pattern matching
        // method on each directory.
        @Override
        public FileVisitResult
            preVisitDirectory(Path dir,
                BasicFileAttributes attrs) {
            find(dir);
            return CONTINUE;
        }

        @Override
        public FileVisitResult
            visitFileFailed(Path file,
                IOException exc) {
            System.err.println(exc);
            return CONTINUE;
        }
    }

    static void usage() {
        System.err.println("java Find <path>" +
            " -name \"<glob_pattern>\"");
        System.exit(-1);
    }

    public static void main(String[] args)
        throws IOException {

        if (args.length < 3 
            || !args[1].equals("-name"))
            usage();

        Path startingDir = Paths.get(args[0]);
        String pattern = args[2];

        Finder finder = new Finder(pattern);
        Files.walkFileTree(startingDir, finder);
        finder.done();
    }
}

On my system (Linux / Fedora), it worked well; however, I was only testing it for functionality, and playing around with it. I didn't stress test it for performance or any other meaningful measurement (beyond "it works").

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
0

Use Files.walkFileTree.

(Have no experience using it, but I just found it in the docs and it looks straightforward to use.)

trutheality
  • 23,114
  • 6
  • 54
  • 68
  • @EdwinBuck ...yes. I'm not sure what you are trying to address with your comment. – trutheality May 09 '12 at 22:29
  • `Files.walkFileTree` returns a `Path`, and by themselves `Path`s don't do anything. A `FileVisitor` can "walk" the `Path` and "discover" the files within the `Path`, perhaps skipping over files or sub-directories of no interest. Your solution is part of what is needed (as it provides the `Path` part) but without a visitor, you'll never see a `File`. – Edwin Buck May 09 '12 at 22:36
  • @EdwinBuck `Files.walkFileTree` actually returns the "starting file", which would be path that you pass to it. Additionally, it is not usable without a `FileVisitor`, so it would be impossible to "use `Files.walkFileTree`" without implementing a `FileVisitor` that does the actual work. It's all very clearly stated in the documentation I linked to. I think this makes my answer sufficient. – trutheality May 09 '12 at 22:43
  • 1
    Link-only answers are redirections, and devinb describes the issues with them better that I. http://meta.stackexchange.com/a/8259/158374 Your answer is sufficient to find the answer, but is actually nothing better than devinb's (modified) quote "I'll direct you to a API information booth, and they will be able to provide you with your answer and much more!" – Edwin Buck May 09 '12 at 22:51
  • @EdwinBuck I'd rather point a man to the fishing school than give him a fish and a dolphin when he asks "does anyone 'round here fish?" – trutheality May 09 '12 at 23:09