Перечислите все файлы из каталога рекурсивно с Java

У меня есть эта функция, которая печатает название всех файлов в каталоге рекурсивно. Проблема состоит в том, что мой код является очень медленным, потому что он должен получить доступ к удаленному сетевому устройству с каждым повторением.

Мой план состоит в том, чтобы сначала загрузить все файлы из каталога рекурсивно и затем после этого пройти все файлы с regex для отфильтровывания всех файлов, которые я не хочу. У кого-либо есть лучшее предложение?

public static printFnames(String sDir){
  File[] faFiles = new File(sDir).listFiles();
  for(File file: faFiles){
    if(file.getName().matches("^(.*?)")){
  System.out.println(file.getAbsolutePath());
    }
  if(file.isDirectory()){
   printFnames(file.getAbsolutePath());
  }
  }
}

Это - просто тест позже, я не собираюсь использовать код как это, вместо этого я собираюсь добавить путь и дату модификации каждого файла, который соответствует усовершенствованному regex к массиву.

80
задан Daryl Bennett 8 January 2015 в 20:12
поделиться

3 ответа

Предполагая, что это реальный производственный код, который вы будете писать, я предлагаю использовать решение такого рода, которое уже было решено - Apache Commons IO , в частности FileUtils.listFiles () . Он обрабатывает вложенные каталоги, фильтры (на основе имени, времени модификации и т. Д.).

Например, для вашего регулярного выражения:

Collection files = FileUtils.listFiles(
  dir, 
  new RegexFileFilter("^(.*?)"), 
  DirectoryFileFilter.DIRECTORY
);

Это будет рекурсивно искать файлы, соответствующие регулярному выражению ^ (. *?) , возвращая результаты в виде коллекции.

Стоит отметить, что это будет не быстрее, чем прокатка вашего собственного кода, он делает то же самое - сканирование файловой системы в Java происходит очень медленно. Разница в том, что в версии Apache Commons ошибок не будет.

130
ответ дан 24 November 2019 в 09:45
поделиться

кажется, что это глупый доступ к файловой системе и получение содержимого для каждого подкаталога вместо получения {{1} } все сразу.

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

0
ответ дан 24 November 2019 в 09:45
поделиться

Интерфейс Java для чтения содержимого папок файловой системы не очень производителен (как вы обнаружили). JDK 7 исправляет это с помощью совершенно нового интерфейса для такого рода вещей, который должен принести производительность на уровне родного языка для такого рода операций.

Основная проблема заключается в том, что Java выполняет системный вызов для каждого отдельного файла. На интерфейсе с низкой задержкой это не такая уж большая проблема - но в сети даже с умеренной задержкой это действительно возрастает. Если вы составите профиль вашего алгоритма выше, вы увидите, что большая часть времени тратится на досадный вызов isDirectory() - это потому, что вы совершаете путешествие туда и обратно для каждого вызова isDirectory(). Большинство современных ОС могут предоставить подобную информацию, когда изначально был запрошен список файлов/папок (в отличие от запроса свойств каждого отдельного пути к файлу).

Если вы не можете ждать JDK7, одна из стратегий решения проблемы задержки - перейти на многопоточность и использовать ExecutorService с максимальным числом потоков для выполнения рекурсии. Это не очень хорошо (вам придется иметь дело с блокировкой структур выходных данных), но это будет намного быстрее, чем выполнение в один поток.

Во всех ваших обсуждениях такого рода вещей я настоятельно рекомендую сравнивать с тем, что вы можете сделать, используя родной код (или даже сценарий командной строки, который делает примерно то же самое). Сказать, что на обход сетевой структуры уходит час, значит не так уж много. Если вы скажете нам, что вы можете сделать это за 7 секунд, а на Java это займет час, это привлечет внимание людей.

12
ответ дан 24 November 2019 в 09:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: