Recursively finding only directories with FileUtils.listFiles
Asked Answered
S

6

18

I want to collect a list of all files under a directory, in particular including subdirectories. I like not doing things myself, so I'm using FileUtils.listFiles from Apache Commons IO. So I have something like:

import java.io.File;
import java.util.Collection;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;

public class TestListFiles {
  public static void main(String[] args) {
    Collection<File> found = FileUtils.listFiles(new File("foo"),
        TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
    for (File f : found) {
      System.out.println("Found file: " + f);
    }
  }
}

Problem is, this only appears to find normal files, not directories:

$ mkdir -p foo/bar/baz; touch foo/one_file
$ java -classpath commons-io-1.4.jar:. TestListFiles
Found file: foo/one_file

I'm already passing TrueFileFilter to both of the filters, so I can't think of anything more inclusive. I want it to list: "foo", "foo/one_file", "foo/bar", "foo/bar/baz" (in any order).

I would accept non-FileUtils solutions as well, but it seems silly to have to write my own BFS, or even to collect the set of parent directories from the list I do get. (That would miss empty subdirectories anyway.) This is on Linux, FWIW.

Sanguine answered 23/5, 2009 at 1:50 Comment(0)
S
21

An old answer but this works for me:

FileUtils.listFilesAndDirs(new File(dir), TrueFileFilter.INSTANCE, DirectoryFileFilter.DIRECTORY);

shows both:

I use:

FileUtils.listFilesAndDirs(new File(dir), new NotFileFilter(TrueFileFilter.INSTANCE), DirectoryFileFilter.DIRECTORY)

Only shows directories and not files...

Sloane answered 17/10, 2012 at 16:21 Comment(3)
This was much slower for me than user573041's answer to the point I killed my app.Dari
A substitute for "new NotFileFilter(TrueFileFilter.INSTANCE)" is just "FalseFileFilter.INSTANCE". I think your answer using "FileUtils.listFilesAndDirs(...)" fits the best, a simple solution the OP asks for.Twibill
I use Collection<File> c = FileUtils.listFilesAndDirs(new File("target"), FalseFileFilter.INSTANCE,TrueFileFilter.INSTANCE);Tallia
K
8

Have you tried simply:

File rootFolder = new File(...);
File[] folders = rootFolder.listFiles((FileFilter) FileFilterUtils.directoryFileFilter());

It seems to work for me. You will need recursion, of course.

Hope it helps.

Kelby answered 1/2, 2011 at 10:24 Comment(2)
Thank you, this one works best for me. I don't want to add another library for VFS.Dari
The problem is that Java io is horribly slow.Spindlelegs
G
6

If you look at the source code and read between the lines in the JavaDoc, you will see that -- unfortunately -- this API is not designed to do what you want. It will return a list of files (not a list of files and directories) that match the provided arguments. In the source code -- look at the method innerListFiles -- you will see that directories are searched and not added to the result list.

I am not aware of any public API that will do what you want. Hopefully someone else will know of one. Most will probably be a DFS, not a BFS, which may or may not matter for your purposes. (So far, all Java code I've ever looked at that did a directory tree traversal did it via a depth-first search. Which doesn't mean that BFS's aren't out there, of course.)

If you really want a list of everything under a given directory, it's easy enough to roll your own. But I understand your wish to not reinvent the wheel.

Note: It's possible that Apache Commons Finder will support what you need, but this library is in The Commons Sandbox, which means it is more experimental at this stage. It may or may not be complete and it may or may not be maintained. It also may be heavyweight for what you are looking for.

Gerthagerti answered 23/5, 2009 at 2:45 Comment(3)
Thanks for the pointer--I may end up just copying that and making it work. I guess this is what I get for assuming everything that's a file on Linux (directories, links, pipes, devices) is a file by Commons's definition.Sanguine
I would have made the same assumption that you did -- until it didn't work. They really should make their JavaDoc more explicit to make it clear.Gerthagerti
Wow, thanks for the pointer. There's no reference in the javadoc that directories are excluded. I don't know who on earth assumes directories are not files!Ruthful
G
6

I avoid the Java IO libraries in most of my non-trivial applications, preferring Commons VFS instead. I believe a call to this method with the appropriate params will accomplish your goal, but I'll grant its a long way to go for the functionality.

Specifically, this code will do what you want:

    FileObject[] files = fileObject.findFiles(new FileSelector() {
        public boolean includeFile(FileSelectInfo fileInfo)  {
            return fileInfo.getFile().getType() == FileType.FOLDER; }

        public boolean traverseDescendents(FileSelectInfo fileInfo) {
            return true;
        }
    });

where fileObject is an instance of FileObject.

Glandular answered 23/5, 2009 at 4:23 Comment(1)
"This method" is a broken link.Beaner
M
1

An easier+complete Commons VFS solution:

FileSystemManager fsManager = VFS.getManager();
FileObject fileObject = fsManager.resolveFile( "yourFileNameHere" );
FileObject[] files = fileObject.findFiles( new FileTypeSelector( FileType.FOLDER ) )
Magnitude answered 5/2, 2010 at 23:53 Comment(0)
L
0

It should work, based on their API.

Here is my own version of FileUtils, not as complete as Commons IO, it contains only what I need. Search for findFiles or you can use iterate to avoid creating huge lists(sometime/most of the time you just want to do something with those files so collecting them in a List it doesn't makes sense).

Lecherous answered 23/5, 2009 at 2:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.