I want to list all files and directories from a start point using recursion.
Here is my code.

    import java.io.File;
    import java.io.IOException;
    public class RecursiveWalk {
                void recursive (File[] allfiles) throws IOException{    
            for (File file : allfiles) {
                if (file.isDirectory()) {
                    System.out.print("directory:");
                                    System.out.println(file.getCanonicalPath());
                                    recursive (file.listFiles());
                } else {
                    System.out.print("     file:");
                                    System.out.println(file.getCanonicalPath());
                }
            } 
        }
        public static void main(String[] args) throws IOException {
             File f = new File("."); // current directory
             File[] allfiles = f.listFiles();
             RecursiveWalk test = new RecursiveWalk();
             test.recursive(allfiles);
    }
    }

I have tested it with several directories. Some times fails , but i can't understand why.
The message i get is Exception in thread "main" java.lang.NullPointerException refering to for (File file : allfiles).

Dani AI

Generated

Nice catch, . The NPE happens because File.listFiles() is allowed to return null (not just throw) when the target is not a directory or an I/O/permission issue occurs. On Vista/7 those "My Documents/My Music/..." items are junction points with Access Denied ACLs for Everyone, so enumeration fails and your enhanced loop trips over a null array. That matches what you saw, and also explains why it is intermittent across folders. (docs.oracle.com)

If you want clearer output and fewer surprises, I’d keep ’s nio direction but switch to a compact stream walk. It does not follow links unless you pass FOLLOW_LINKS, and it closes directories when the stream is closed. This example prints a simple tree with indentation and labels:

Path start = Paths.get(".");
try (Stream<Path> walk = Files.walk(start)) {   // no FOLLOW_LINKS by default
    walk.forEach(p -> {
        int depth = start.relativize(p).getNameCount();
        String indent = new String(new char[depth]).replace("\0", "  ");
        String kind = Files.isDirectory(p) ? "[D] " : "[F] ";
        System.out.println(indent + kind + p);
    });
}

Notes:

  • If you stay on java.io.File, always guard the result of listFiles() and skip when it is null (unreadable or not a directory). This avoids the NPE entirely. (docs.oracle.com)
  • With nio streams, leave links unfollowed to avoid cycles. If you decide to follow them, add your own visited-set (eg, toRealPath() strings) to prevent infinite loops. (docs.oracle.com)

These tweaks keep your walker robust on Windows junctions and make the output tidier without special-casing Vista paths.

Recommended Answers

All 9 Replies

Debug this by starting at the line where you get the NPE and print the variables there to see which is null, then work back to see how that happened.
From the incomplete info you gave it looks like you have called allFiles() on somethingthat's not a directory, but your code seems to preclude that possibility. You print which files and directories you are processing, so what's different about the dir you are processing when you get the NPE?

I found the problem.
I tested the program using win vista.
The My Documents, My Music, My Pictures, and My Videos folders in Windows Vista are junction points.

That's really interesting - I'm sure a number of people here (including me) will want to know exactly how they appear for isDirectory() and listFiles() - is it the case that isDirectory() returns false, but listFiles() still returns null?
Please share you findings (and solution) with us.
J

To overcome junction points i modified the code :

    import java.io.File;
    import java.nio.file.*;
    import java.io.IOException;
    public class RecursiveWalk {
                void recursive (File[] allfiles) throws IOException{    
                        boolean b;
                        Path myfile;
            for (File file : allfiles) {
                          myfile = Paths.get(file.toString());
                          b = Files.isReadable(myfile);
                if (file.isDirectory() && b) {
                    System.out.print("directory:");
                                    System.out.println(file.getCanonicalPath());
                                    recursive (file.listFiles());
                } else {
                    System.out.print("   s_l or file:");
                                    System.out.println(file.getCanonicalPath());
                }
                    }
        }
        public static void main(String[] args) throws IOException {
             File f = new File("."); //current directory
             File[] allfiles = f.listFiles();
         RecursiveWalk test = new RecursiveWalk();
             test.recursive(allfiles);
    }
    }

Thank you so much for sharing that.
Java 7 has the nio ("new i/o") package that is a modern replacement for the old File class, and apparently has proper built-in support for junction points. That's where your Files.isReadable method comes from. Presumably the ideal solution would be upgrade this whole thing to nio and use the FileVistor interface to walk the tree.

http://docs.oracle.com/javase/tutorial/essential/io/fileio.html

Thanks. I'll come back with a new nio version.

Using this http://docs.oracle.com/javase/tutorial/essential/io/walk.html 
wrote a new version. But the output is not as clear as it was with the previous version.
Needs correction.

    import java.nio.file.Path;
    import java.nio.file.FileVisitResult;
    import java.nio.file.SimpleFileVisitor;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.nio.file.attribute.BasicFileAttributes;

    public  class PrintFiles  extends SimpleFileVisitor<Path> {

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
            if (attr.isSymbolicLink()) {
                System.out.println("Symbolic link: " + file.toString());
            } else if (attr.isRegularFile()) {
                System.out.println("Regular file: " + file.toString());
            } else {
                System.out.println("Other: " + file.toString());
            }

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

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

        public static void main(String[] args){
            Path StartPoint = Paths.get(".");
            PrintFiles walk = new PrintFiles();
           // EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        try {
              Files.walkFileTree(StartPoint, walk);
           // Files.walkFileTree(StartPoint, opts, Integer.MAX_VALUE, walk);

        }catch(IOException e){
            System.out.println(e);
        }
          }
    }

I guess as long as it's getting all the correct info then tarting up the output will be the easiest (if maybe a bit tedious) part :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.