Я только что завершил тестовые результаты, которые предоставляют тесты производительности для многих ответов. Неудивительно, что все ответы на основе NIO работают лучше всего. Ответ от commons-io явно худший, более чем вдвое больше.
Бретт Райан
2
Java8: Files.walk?
Бендж
Ответы:
327
Java 8 предоставляет хороший поток для обработки всех файлов в дереве.
Это обеспечивает естественный способ обхода файлов. Поскольку это поток, вы можете выполнять все приятные потоковые операции с результатом, такие как ограничение, группировка, отображение, ранний выход и т. Д.
ОБНОВЛЕНИЕ : Я мог бы указать, что есть также Files.find, который принимает BiPredicate, который может быть более эффективным, если вам нужно проверить атрибуты файла.
Обратите внимание, что, хотя JavaDoc не допускает, что этот метод может быть более эффективным, чем Files.walk, он фактически идентичен, различие в производительности можно наблюдать, если вы также извлекаете атрибуты файла в своем фильтре. В конце концов, если вам нужно фильтровать атрибуты, используйте Files.find , в противном случае используйте Files.walk. , в основном из-за перегрузок, и это более удобно.
Один из тех примеров, которые могут показать магию функционального программирования даже для начинающих.
Джонни
2
Как производительность по сравнению с до-Java 8 методов? Мой текущий просмотр каталога слишком медленный, и я ищу что-то, что ускорит его.
Шридхар Сарнобат
1
Я пишу некоторые тесты, содержащие большинство вариантов в ответах. До сих пор кажется, что использование Files.walkс параллельным потоком является лучшим, за которым следует, Files.walkFileTreeчто только немного медленнее. Принятый ответ с использованием commons-io, безусловно, самый медленный по моим тестам, в 4 раза медленнее.
Бретт Райан
1
@BrettRyan, я попробовал ваше решение, но получил исключение Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. Как я мог это исправить
Качна
5
Как мне получить фактический список файлов из этого?
Изменить: вы можете проверить здесь для сравнения различных подходов. Кажется, что подход commons-io медленный, поэтому выберите некоторые из более быстрых отсюда (если это имеет значение)
FYI / TLDR: если вы хотите просто рекурсивно перечислить все файлы без фильтрации, выполните команду « FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)Где», где dirнаходится объект «Файл», указывающий на базовый каталог.
andronikus
2
Вы можете рассмотреть возможность использования listFilesAndDirs(), так как listFiles()не возвращает пустые папки.
шнаттерер
1
@MikeFHay Глядя на код FileUtils, я думаю, что это будет FileUtils.listFiles(dir, true, true). Использование FileUtils.listFiles(dir, null, true)выдаст исключение, а FileUtils.listFiles(dir, true, null)перечислит все файлы, не заглядывая в подкаталоги.
Окрамот
Как насчет нативной библиотеки JDK? Я могу реализовать это легко, но я просто буду C & P из других мест
Кристиан Бонджорно
1
Я собираю некоторые тесты вместе, но пока, похоже, это работает в 4 раза медленнее, чем при использовании альтернатив JDK8 или JDK7. Символьные ссылки также оказываются проблематичными с этим подходом, особенно когда они ссылаются на каталоги выше в дереве, это приводит к тому, что метод никогда не возвращается, этого можно избежать, обрабатывая фильтр, но, к сожалению, сами символические ссылки не посещаются, даже если файл.
Бретт Райан
138
// Готов для запуска
import java.io.File;publicclassFilewalker{publicvoid walk(String path ){File root =newFile( path );File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f.getAbsolutePath());System.out.println("Dir:"+ f.getAbsoluteFile());}else{System.out.println("File:"+ f.getAbsoluteFile());}}}publicstaticvoid main(String[] args){Filewalker fw =newFilewalker();
fw.walk("c:\\");}}
Просто помните, что для символических ссылок, которые указывают путь выше в иерархии путей, метод никогда не закончится. Рассмотрим путь с символической ссылкой, которая указывает на -> ..
Бретт Райан
2
Это просто плохая реализация Files.walkFileTree. Я бы порекомендовал, чтобы люди смотрели на FIles.walkFileTree вместо того, чтобы пытаться свернуть его сами ... У него есть обработка для точной проблемы, которую указал @BrettRyan.
Тайлер Николс
Спасибо, что включили импорт java.io.File ;. Многие примеры забывают включать в себя материал пространства имен или даже тип данных, что делает этот пример отправной точкой в путешествии открытий. Вот этот пример готов к запуску. Спасибо.
barrypicker
Путь может варьироваться в зависимости от того, где находится файл Filewalker. Используйте "/", "./"или "../"для корневого каталога, текущий рабочий каталог и родительский каталог соответственно
Если вы укажете начальную точку и посетителя файла, он будет вызывать различные методы для посетителя файла, когда он просматривает файл в дереве файлов. Мы ожидаем, что люди будут использовать это, если они разрабатывают рекурсивную копию, рекурсивное перемещение, рекурсивное удаление или рекурсивную операцию, которая устанавливает разрешения или выполняет другую операцию для каждого из файлов.
publicvoid list(File file){System.out.println(file.getName());File[] children = file.listFiles();for(File child : children){
list(child);}}
System.out.println просто указывает, что нужно что-то делать с файлом. нет необходимости различать файлы и каталоги, так как обычный файл просто не имеет дочерних элементов.
Пожалуйста! позвольте вызывающему инициализировать список файлов, чтобы ему не приходилось каждый раз проверять его недействительность. Если вы хотите создать второй (публичный) метод, который создает список, вызывает этот внутренний метод и возвращает полный список.
Гелиос
1
без разницы. нулевая проверка не очень дорога, кроме удобства и личных предпочтений, я думаю, он поймет.
pstanton
Можете ли вы объяснить более многословно?
Uday
8
Я думаю, что это должно сделать работу:
File dir =newFile(dirname);String[] files = dir.list();
Таким образом, у вас есть файлы и каталоги. Теперь используйте рекурсию и сделайте то же самое для dirs (у Fileкласса есть isDirectory()метод).
Помимо рекурсивного обхода можно использовать подход на основе Visitor.
В приведенном ниже коде используется подход, основанный на посетителях, для обхода. Ожидается, что вход в программу является корневым каталогом для прохождения.
Общепринятый ответ велик, однако он ломается , когда вы хотите сделать IO внутри лямбда.
Вот что вы можете сделать, если ваше действие объявляет IOExceptions.
Вы можете рассматривать отфильтрованный поток как Iterable, а затем выполнять свои действия в обычном цикле for-each. Таким образом, вам не нужно обрабатывать исключения внутри лямбды.
try(Stream<Path> pathStream =Files.walk(Paths.get(path)).filter(Files::isRegularFile)){for(Path file :(Iterable<Path>) pathStream::iterator){// something that throws IOExceptionFiles.copy(file,System.out);}}
После публикации этого примера у меня возникли проблемы с пониманием того, как передать параметр имени файла в примере №1, заданном Брайаном, с использованием foreach в Stream-result -
На основании ответа укладчика. Вот решение, работающее в JSP без каких-либо внешних библиотек, поэтому вы можете разместить его практически в любом месте на вашем сервере:
<!DOCTYPE html><%@ page session="false"%><%@ page import="java.util.*"%><%@ page import="java.io.*"%><%@ page contentType="text/html; charset=UTF-8"%><%!publicList<String> files =newArrayList<String>();/**
Fills files array with all sub-files.
*/publicvoid walk(File root ){File[] list = root.listFiles();if(list ==null)return;for(File f : list ){if( f.isDirectory()){
walk( f );}else{
files.add(f.getAbsolutePath());}}}%><%
files.clear();File jsp =newFile(request.getRealPath(request.getServletPath()));File dir = jsp.getParentFile();
walk(dir);String prefixPath = dir.getAbsolutePath()+"/";%>
Хотя это, вероятно, работает, вопрос касается просмотра файлов, а не рендеринга просматриваемых файлов. Лучше представить свой алгоритм как таковой, не рекомендуется встраивать бизнес-логику в JSP.
Самуэль Керриен
Это зависит от того, что вы делаете. В приложении корпоративного размера вы абсолютно правы. Если вам просто нужно добавить это в простой, автономный список, то это прекрасно.
Ответы:
Java 8 предоставляет хороший поток для обработки всех файлов в дереве.
Это обеспечивает естественный способ обхода файлов. Поскольку это поток, вы можете выполнять все приятные потоковые операции с результатом, такие как ограничение, группировка, отображение, ранний выход и т. Д.
ОБНОВЛЕНИЕ : Я мог бы указать, что есть также Files.find, который принимает BiPredicate, который может быть более эффективным, если вам нужно проверить атрибуты файла.
Обратите внимание, что, хотя JavaDoc не допускает, что этот метод может быть более эффективным, чем Files.walk, он фактически идентичен, различие в производительности можно наблюдать, если вы также извлекаете атрибуты файла в своем фильтре. В конце концов, если вам нужно фильтровать атрибуты, используйте Files.find , в противном случае используйте Files.walk. , в основном из-за перегрузок, и это более удобно.
ИСПЫТАНИЯ : В соответствии с просьбой я дал сравнение производительности многих ответов. Проверьте проект Github, который содержит результаты и контрольный пример .
источник
Files.walk
с параллельным потоком является лучшим, за которым следует,Files.walkFileTree
что только немного медленнее. Принятый ответ с использованием commons-io, безусловно, самый медленный по моим тестам, в 4 раза медленнее.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. Как я мог это исправитьУ FileUtils есть
iterateFiles
иlistFiles
методы. Дай им попробовать. (из общего достояния )Изменить: вы можете проверить здесь для сравнения различных подходов. Кажется, что подход commons-io медленный, поэтому выберите некоторые из более быстрых отсюда (если это имеет значение)
источник
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
Где», гдеdir
находится объект «Файл», указывающий на базовый каталог.listFilesAndDirs()
, так какlistFiles()
не возвращает пустые папки.FileUtils.listFiles(dir, true, true)
. ИспользованиеFileUtils.listFiles(dir, null, true)
выдаст исключение, аFileUtils.listFiles(dir, true, null)
перечислит все файлы, не заглядывая в подкаталоги.// Готов для запуска
источник
-> .
."/"
,"./"
или"../"
для корневого каталога, текущий рабочий каталог и родительский каталог соответственноJava 7
будет иметьимеет Files.walkFileTree :В настоящее время существует целый учебник Oracle по этому вопросу .
источник
Внешние библиотеки не нужны.
Возвращает коллекцию, чтобы вы могли делать с ней все, что захотите после звонка.
источник
Я хотел бы пойти с чем-то вроде:
System.out.println просто указывает, что нужно что-то делать с файлом. нет необходимости различать файлы и каталоги, так как обычный файл просто не имеет дочерних элементов.
источник
listFiles()
: «Если это абстрактное имя пути не обозначает каталог, то этот метод возвращаетnull
».Я предпочитаю использовать очередь, а не рекурсию для такого простого прохождения:
источник
просто напишите это самостоятельно, используя простую рекурсию:
источник
Я думаю, что это должно сделать работу:
Таким образом, у вас есть файлы и каталоги. Теперь используйте рекурсию и сделайте то же самое для dirs (у
File
класса естьisDirectory()
метод).источник
С Java 7 вы можете использовать следующий класс:
источник
В Java 8 теперь мы можем использовать утилиту Files для обхода файлового дерева. Очень просто.
источник
Этот код готов к запуску
источник
Помимо рекурсивного обхода можно использовать подход на основе Visitor.
В приведенном ниже коде используется подход, основанный на посетителях, для обхода. Ожидается, что вход в программу является корневым каталогом для прохождения.
источник
Вы можете использовать приведенный ниже код, чтобы получить список файлов определенной папки или каталога рекурсивно.
источник
Общепринятый ответ велик, однако он ломается , когда вы хотите сделать IO внутри лямбда.
Вот что вы можете сделать, если ваше действие объявляет IOExceptions.
Вы можете рассматривать отфильтрованный поток как
Iterable
, а затем выполнять свои действия в обычном цикле for-each. Таким образом, вам не нужно обрабатывать исключения внутри лямбды.Нашел этот трюк здесь: https://stackoverflow.com/a/32668807/1207791
источник
Нерекурсивная BFS с одним списком (конкретный пример - поиск файлов * .eml):
источник
Моя версия (конечно, я мог бы использовать встроенную прогулку в Java 8 ;-)):
источник
Вот простое, но отлично работающее решение с использованием
recursion
:источник
источник
Я придумал это для рекурсивной печати всех файлов / имен файлов.
источник
Пример выводит файлы * .csv в подкаталоги рекурсивного поиска в каталоге с помощью Files.find () из java.nio:
После публикации этого примера у меня возникли проблемы с пониманием того, как передать параметр имени файла в примере №1, заданном Брайаном, с использованием foreach в Stream-result -
Надеюсь это поможет.
источник
Котлин
FileTreeWalk
для этого есть. Например:Будет создан текстовый список всех не-каталогов файлов в данном корне, один файл на строку с путем относительно корня и длины.
источник
Еще один способ сделать это можно, даже если кто-то уже предоставил Java 8 walk.
Этот предоставит вам все файлы рекурсивно
источник
На основании ответа укладчика. Вот решение, работающее в JSP без каких-либо внешних библиотек, поэтому вы можете разместить его практически в любом месте на вашем сервере:
Тогда вы просто делаете что-то вроде:
источник