Рекурсивно список файлов в Java
Как рекурсивно перечислить все файлы в каталоге на Java? Не предусматривают какую-либо полезность?
Я видел много реализаций суховато. Но ни один из рамок или НИО
20 ответов:
Java 8 предоставляет хороший поток для обработки всех файлов в дереве.
Files.walk(Paths.get(path)) .filter(Files::isRegularFile) .forEach(System.out::println);Это обеспечивает естественный способ обхода файлов. Поскольку это поток, вы можете выполнять все хорошие операции потока над результатом, такие как ограничение, группировка, отображение, ранний выход и т. д.
обновление: я мог бы указать, что есть также файлы.найти что происходит BiPredicate это может быть более эффективным, если вам нужно проверить файл атрибуты.
Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile()) .forEach(System.out::println);обратите внимание, что в то время как JavaDoc ускользает, что этот метод может быть более эффективным, чем файлы.гуляй он фактически идентичен, разница в производительности может наблюдаться, если вы также извлекаете атрибуты файла в своем фильтре. В конце концов, если вам нужно фильтровать по атрибутам, использовать файлы.найти, в противном случае используйте файлы.гуляй в основном, потому что нет перегрузок и больше удобный.
тесты: по запросу я предоставил сравнение производительности многих ответов. Проверьте проект Github, который содержит результаты и тестовый случай.
FileUtils есть
iterateFilesиlistFilesметоды. Дайте им попробовать. (от commons-io)редактировать: вы можете регистрация здесь для сравнения различных подходов. Похоже, что подход commons-io медленный, поэтому выберите некоторые из более быстрых отсюда (если это важно)
// готов к запуску
import java.io.File; public class Filewalker { public void walk( String path ) { File root = new File( 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() ); } } } public static void main(String[] args) { Filewalker fw = new Filewalker(); fw.walk("c:\" ); } }
Java 7
будети файлы.walkFileTree:Если вы укажете начальную точку и посетителя файла, он будет вызывать различные методы для посетителя файла, когда он проходит через файл в дереве файлов. Мы ожидаем, что люди будут использовать это, если они разрабатывают рекурсивную копию, рекурсивное перемещение, рекурсивное удаление или рекурсивную операцию, которая устанавливает разрешения или выполняет другую операцию на каждом из файлы.
теперь есть целый учебник Oracle по этому вопросу.
внешние библиотеки не нужны.
возвращает коллекцию, так что вы можете делать все, что вы хотите с ним после звонка.public static Collection<File> listFileTree(File dir) { Set<File> fileTree = new HashSet<File>(); if(dir==null||dir.listFiles()==null){ return fileTree; } for (File entry : dir.listFiles()) { if (entry.isFile()) fileTree.add(entry); else fileTree.addAll(listFileTree(entry)); } return fileTree; }
Я бы пошел с что-то вроде:
public void list(File file) { System.out.println(file.getName()); File[] children = file.listFiles(); for (File child : children) { list(child); } }Система.из.println просто указывает, что нужно что-то сделать с файлом. нет необходимости различать файлы и каталоги, так как обычный файл будет просто иметь нулевых детей.
просто написать его самостоятельно, используя простую рекурсию:
public List<File> addFiles(List<File> files, File dir) { if (files == null) files = new LinkedList<File>(); if (!dir.isDirectory()) { files.add(dir); return files; } for (File file : dir.listFiles()) addFiles(files, file); return files; }
Я предпочитаю использовать очередь над рекурсией для такого рода простого обхода:
List<File> allFiles = new ArrayList<File>(); Queue<File> dirs = new LinkedList<File>(); dirs.add(new File("/start/dir/")); while (!dirs.isEmpty()) { for (File f : dirs.poll().listFiles()) { if (f.isDirectory()) { dirs.add(f); } else if (f.isFile()) { allFiles.add(f); } } }
С Java 7 Вы можете использовать следующий класс:
import java.io.IOException; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; public class MyFileIterator extends SimpleFileVisitor<Path> { public MyFileIterator(String path) throws Exception { Files.walkFileTree(Paths.get(path), this); } @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attributes) throws IOException { System.out.println("File: " + file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attributes) throws IOException { System.out.println("Dir: " + dir); return FileVisitResult.CONTINUE; } }
Я думаю, что это должно сделать работу:
File dir = new File(dirname); String[] files = dir.list();таким образом у вас есть файлы и каталоги. Теперь используйте рекурсию и сделайте то же самое для dirs (
FileклассisDirectory()метод).
в Java 8 Теперь мы можем использовать утилиту Files для обхода дерева файлов. Очень просто.
Files.walk(root.toPath()) .filter(path -> !Files.isDirectory(path)) .forEach(path -> System.out.println(path));
помимо рекурсивного обхода можно также использовать подход, основанный на посетителе.
ниже код использует подход на основе посетителей для traversal.It ожидается, что вход в программу является корневым каталогом для обхода.
public interface Visitor { void visit(DirElement d); void visit(FileElement f); } public abstract class Element { protected File rootPath; abstract void accept(Visitor v); @Override public String toString() { return rootPath.getAbsolutePath(); } } public class FileElement extends Element { FileElement(final String path) { rootPath = new File(path); } @Override void accept(final Visitor v) { v.visit(this); } } public class DirElement extends Element implements Iterable<Element> { private final List<Element> elemList; DirElement(final String path) { elemList = new ArrayList<Element>(); rootPath = new File(path); for (File f : rootPath.listFiles()) { if (f.isDirectory()) { elemList.add(new DirElement(f.getAbsolutePath())); } else if (f.isFile()) { elemList.add(new FileElement(f.getAbsolutePath())); } } } @Override void accept(final Visitor v) { v.visit(this); } public Iterator<Element> iterator() { return elemList.iterator(); } } public class ElementWalker { private final String rootDir; ElementWalker(final String dir) { rootDir = dir; } private void traverse() { Element d = new DirElement(rootDir); d.accept(new Walker()); } public static void main(final String[] args) { ElementWalker t = new ElementWalker("C:\temp"); t.traverse(); } private class Walker implements Visitor { public void visit(final DirElement d) { System.out.println(d); for(Element e:d) { e.accept(this); } } public void visit(final FileElement f) { System.out.println(f); } } }
вы можете использовать ниже код, чтобы получить список файлов из определенной папки или директории рекурсивно.
public static void main(String args[]) { recusiveList("D:"); } public static void recursiveList(String path) { File f = new File(path); File[] fl = f.listFiles(); for (int i = 0; i < fl.length; i++) { if (fl[i].isDirectory() && !fl[i].isHidden()) { System.out.println(fl[i].getAbsolutePath()); recusiveList(fl[i].getAbsolutePath()); } else { System.out.println(fl[i].getName()); } } }
этот код готов к запуску
public static void main(String... args) { File[] files = new File("D:/").listFiles(); if (files != null) getFile(files); } public static void getFile(File[] files) { for (File file : files) { if (file.isDirectory()) { getFile(file.listFiles()); } else { System.out.println("File: " + file); } } }
нерекурсивная BFS с одним списком (конкретный пример-поиск *.eml files):
final FileFilter filter = new FileFilter() { @Override public boolean accept(File file) { return file.isDirectory() || file.getName().endsWith(".eml"); } }; // BFS recursive search List<File> queue = new LinkedList<File>(); queue.addAll(Arrays.asList(dir.listFiles(filter))); for (ListIterator<File> itr = queue.listIterator(); itr.hasNext();) { File file = itr.next(); if (file.isDirectory()) { itr.remove(); for (File f: file.listFiles(filter)) itr.add(f); } }
моя версия (конечно, я мог бы использовать встроенный walk в Java 8 ; -)):
public static List<File> findFilesIn(File rootDir, Predicate<File> predicate) { ArrayList<File> collected = new ArrayList<>(); walk(rootDir, predicate, collected); return collected; } private static void walk(File dir, Predicate<File> filterFunction, List<File> collected) { Stream.of(listOnlyWhenDirectory(dir)) .forEach(file -> walk(file, filterFunction, addAndReturn(collected, file, filterFunction))); } private static File[] listOnlyWhenDirectory(File dir) { return dir.isDirectory() ? dir.listFiles() : new File[]{}; } private static List<File> addAndReturn(List<File> files, File toAdd, Predicate<File> filterFunction) { if (filterFunction.test(toAdd)) { files.add(toAdd); } return files; }
пример выхода *.csv файлы в каталоге рекурсивный поиск подкаталогов с использованием файлов.найти() из Java.НИО:
String path = "C:/Daten/ibiss/ferret/"; logger.debug("Path:" + path); try (Stream<Path> fileList = Files.find(Paths.get(path), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile() && filePath.toString().endsWith("csv"))) { List<String> someThingNew = fileList.sorted().map(String::valueOf).collect(Collectors.toList()); for (String t : someThingNew) { t.toString(); logger.debug("Filename:" + t); } }публикация этого примера, поскольку у меня возникли проблемы с пониманием того, как передать параметр filename в Примере #1, приведенном Брайаном, используя foreach on Stream-result -
надеюсь, что это помогает.
здесь простое, но прекрасно работающее решение с помощью
recursion:public static List<Path> listFiles(String rootDirectory) { List<Path> files = new ArrayList<>(); listFiles(rootDirectory, files); return files; } private static void listFiles(String path, List<Path> collectedFiles) { File root = new File(path); File[] files = root.listFiles(); if (files == null) { return; } for (File file : files) { if (file.isDirectory()) { listFiles(file.getAbsolutePath(), collectedFiles); } else { collectedFiles.add(file.toPath()); } } }
private void fillFilesRecursively(File file, List<File> resultFiles) { if (file.isFile()) { resultFiles.add(file); } else { for (File child : file.listFiles()) { fillFilesRecursively(child, resultFiles); } } }
основанный на ответе штабелеукладчика. Вот решение, работающее в JSP без каких-либо внешних библиотек, так что вы можете поместить его почти в любом месте на вашем сервере:
<!DOCTYPE html> <%@ page session="false" %> <%@ page import="java.util.*" %> <%@ page import="java.io.*" %> <%@ page contentType="text/html; charset=UTF-8" %> <%! public List<String> files = new ArrayList<String>(); /** Fills files array with all sub-files. */ public void 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 = new File(request.getRealPath(request.getServletPath())); File dir = jsp.getParentFile(); walk(dir); String prefixPath = dir.getAbsolutePath() + "/"; %>тогда вы просто делаете что-то вроде:
<ul> <% for (String file : files) { %> <% if (file.matches(".+\.(apk|ipa|mobileprovision)")) { %> <li><%=file.replace(prefixPath, "")%></li> <% } %> <% } %> </ul>
Comments