Рекурсивный поиск только каталогов с FileUtils.listFiles

Я хочу собрать список всех файлов в каталоге, в частности, включая подкаталоги. Мне нравится ничего не делать самому, поэтому я использую FileUtils.listFiles из Apache Commons IO. Итак, у меня есть что-то вроде:

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);
    }
  }
}

Проблема в том, что это похоже только на обычные файлы, а не на каталоги:

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

Я уже передаю TrueFileFilter обоим фильтрам, поэтому не могу придумать ничего более всеобъемлющего. Я хочу, чтобы он отображал: "foo", "foo/one_file", "foo/bar", "foo/bar/baz" (в любом порядке).

Я бы также принял решения, отличные от FileUtils, но кажется глупым писать свою собственную BFS или даже собирать набор родительских каталогов из списка, который я получаю. (Это в любом случае пропустит пустые подкаталоги.) Это в Linux, FWIW.


person Dave B    schedule 23.05.2009    source источник


Ответы (6)


Старый ответ, но это работает для меня:

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

показывает оба:

Я использую:

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

Показывает только каталоги, а не файлы...

person DOS    schedule 17.10.2012
comment
Для меня это было намного медленнее, чем ответ пользователя 573041 на тот момент, когда я убил свое приложение. - person Sridhar Sarnobat; 22.02.2014
comment
Заменой для нового NotFileFilter(TrueFileFilter.INSTANCE) является просто FalseFileFilter.INSTANCE. Я думаю, что ваш ответ с использованием FileUtils.listFilesAndDirs(...) подходит лучше всего, это простое решение, о котором просит OP. - person It's Leto; 03.07.2015
comment
Я использую Collection‹File› c = FileUtils.listFilesAndDirs(new File(target), FalseFileFilter.INSTANCE,TrueFileFilter.INSTANCE); - person Anver Sadhat; 31.08.2016

Вы пробовали просто:

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

Кажется, это работает для меня. Конечно, вам понадобится рекурсия.

Надеюсь, поможет.

person user573041    schedule 01.02.2011
comment
Спасибо, это лучше всего подходит для меня. Я не хочу добавлять еще одну библиотеку для VFS. - person Sridhar Sarnobat; 22.02.2014
comment
Проблема в том, что Java io ужасно медленный. - person Kieveli; 08.07.2014

Я избегаю библиотек Java IO в большинстве своих нетривиальных приложений, вместо этого предпочитая Commons VFS. Я считаю, что вызов этот метод с соответствующими параметрами достигнет вашей цели, но я согласен, что для функциональности ему предстоит пройти долгий путь.

В частности, этот код будет делать то, что вы хотите:

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

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

где fileObject является экземпляром FileObject.

person Jherico    schedule 23.05.2009
comment
Этот метод является неработающей ссылкой. - person Dave Jarvis; 18.09.2013

Если вы посмотрите на исходный код и прочтите JavaDoc между строк, вы увидите, что, к сожалению, этот API не предназначен для того, чтобы делать то, что вам нужно. Он вернет список файлов (а не список файлов и каталогов), соответствующих указанным аргументам. В исходном коде — взгляните на метод innerListFiles — вы увидите, что каталоги ищутся и не добавляются в список результатов.

Я не знаю ни одного общедоступного API, который будет делать то, что вы хотите. Надеюсь, кто-то еще узнает об одном. Большинство из них, вероятно, будут DFS, а не BFS, что может иметь или не иметь значения для ваших целей. (До сих пор весь Java-код, который я когда-либо видел, выполнял обход дерева каталогов с помощью поиска в глубину. Это, конечно, не означает, что BFS не существуют. .)

Если вам действительно нужен список всего в заданном каталоге, достаточно легко составить свой собственный. Но я понимаю ваше желание не изобретать велосипед.

Примечание. Возможно, что Apache Commons Finder будет поддерживать то, что вам нужно, но эта библиотека находится в Песочница Commons, что означает, что на данном этапе она является более экспериментальной. Он может быть или не быть полным, и он может поддерживаться или не поддерживаться. Это также может быть тяжеловесом для того, что вы ищете.

person Eddie    schedule 23.05.2009
comment
Спасибо за указание - я могу в конечном итоге просто скопировать это и заставить его работать. Я думаю, это то, что я получаю, предполагая, что все, что является файлом в Linux (каталоги, ссылки, каналы, устройства), является файлом по определению Коммонса. - person Dave B; 23.05.2009
comment
Я бы сделал то же предположение, что и вы - пока это не сработало. Они действительно должны сделать свой JavaDoc более явным, чтобы сделать его понятным. - person Eddie; 23.05.2009
comment
Вау, спасибо за указатель. В javadoc нет ссылки на то, что каталоги исключены. Я не знаю, кто на земле предполагает, что каталоги не являются файлами! - person WhyNotHugo; 07.05.2012

Более простое и полное решение Commons VFS:

FileSystemManager fsManager = VFS.getManager();
FileObject fileObject = fsManager.resolveFile( "yourFileNameHere" );
FileObject[] files = fileObject.findFiles( new FileTypeSelector( FileType.FOLDER ) )
person javamonkey79    schedule 05.02.2010

Это должно работать, основываясь на их API.

Вот моя собственная версия FileUtils, не такой полный, как Commons IO, он содержит только то, что мне нужно. Найдите findFiles или используйте itate, чтобы избежать создания огромных списков (иногда/в большинстве случаев вы просто хотите что-то сделать с этими файлами, поэтому собирайте их в список). не имеет смысла).

person adrian.tarau    schedule 23.05.2009