subcarpetas - Listar recursivamente archivos en Java
mostrar carpetas java (20)
// Listo para correr
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://" );
}
}
¿Cómo hago una lista recursiva de todos los archivos en un directorio en Java? ¿El marco proporciona alguna utilidad?
Vi muchas implementaciones hacky. Pero ninguno del marco o nio
Aparte del recorrido recursivo, también se puede utilizar un enfoque basado en el visitante.
El código a continuación utiliza el enfoque basado en el visitante para el recorrido. Se espera que la entrada al programa sea el directorio raíz a recorrer.
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);
}
}
}
Aquí una solución simple pero perfectamente funcional utilizando la 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());
}
}
}
BFS no recursivo con una sola lista (el ejemplo particular busca archivos * .eml):
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);
}
}
Basado en la respuesta del apilador. Aquí hay una solución que funciona en JSP sin bibliotecas externas para que pueda ponerla en casi cualquier lugar de su servidor:
<!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() + "/";
%>
Entonces solo haces algo como:
<ul>
<% for (String file : files) { %>
<% if (file.matches(".+//.(apk|ipa|mobileprovision)")) { %>
<li><%=file.replace(prefixPath, "")%></li>
<% } %>
<% } %>
</ul>
Con Java 7 puedes usar la siguiente clase:
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;
}
}
Creo que esto debería hacer el trabajo:
File dir = new File(dirname);
String[] files = dir.list();
De esta manera tienes archivos y directorios. Ahora use recursión y haga lo mismo para dirs (la clase de File
tiene el método isDirectory()
).
Ejemplo produce archivos * .csv en directorios de búsqueda recursiva usando Files.find () de java.nio:
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);
}
}
Publicar este ejemplo, ya que tuve problemas para entender cómo pasar el parámetro de nombre de archivo en el ejemplo # 1 dado por Bryan, usando foreach en Stream-result -
Espero que esto ayude.
En Java 8, ahora podemos usar la utilidad Archivos para recorrer un árbol de archivos. Muy simple.
Files.walk(root.toPath())
.filter(path -> !Files.isDirectory(path))
.forEach(path -> System.out.println(path));
Iría con algo como:
public void list(File file) {
System.out.println(file.getName());
File[] children = file.listFiles();
for (File child : children) {
list(child);
}
}
El System.out.println está justo ahí para indicar que se haga algo con el archivo. no hay necesidad de diferenciar entre archivos y directorios, ya que un archivo normal simplemente tendrá cero hijos.
Java 7 tendrá tiene Files.walkFileTree :
Si proporciona un punto de partida y un visitante de archivo, invocará varios métodos en el visitante de archivo a medida que recorre el archivo en el árbol de archivos. Esperamos que las personas utilicen esto si están desarrollando una copia recursiva, un movimiento recursivo, una eliminación recursiva o una operación recursiva que establece permisos o realiza otra operación en cada uno de los archivos.
Ahora hay un tutorial completo de Oracle sobre esta pregunta .
Java 8 proporciona una buena secuencia para procesar todos los archivos en un árbol.
Files.walk(Paths.get(path))
.filter(Files::isRegularFile)
.forEach(System.out::println);
Esto proporciona una forma natural de atravesar archivos. Ya que es un flujo, puede realizar todas las operaciones de flujo agradable en el resultado, como límite, agrupación, mapeo, salida temprana, etc.
ACTUALIZACIÓN : Podría señalar que también hay Files.find que toma un BiPredicate que podría ser más eficiente si necesita verificar los atributos del archivo.
Files.find(Paths.get(path),
Integer.MAX_VALUE,
(filePath, fileAttr) -> fileAttr.isRegularFile())
.forEach(System.out::println);
Tenga en cuenta que si bien JavaDoc elude que este método podría ser más eficiente que Files.walk realidad es idéntico, se puede observar la diferencia en el rendimiento si también está recuperando atributos de archivo dentro de su filtro. Al final, si necesita filtrar por atributos, use Files.find ; de lo contrario, use Files.walk , principalmente porque hay sobrecargas y es más conveniente.
PRUEBAS : Según lo solicitado, proporcioné una comparación de rendimiento de muchas de las respuestas. Echa un vistazo al proyecto Github que contiene resultados y un caso de prueba .
Mi versión (por supuesto, podría haber usado el walk in incorporado en 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;
}
No se necesitan bibliotecas externas.
Devuelve una Colección para que pueda hacer lo que quiera con ella después de la llamada.
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;
}
Prefiero usar una cola en lugar de recursión para este tipo de travesía simple:
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);
}
}
}
Puede usar el código de abajo para obtener una lista de archivos de una carpeta o directorio específico de forma recursiva.
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());
}
}
}
Solo escríbelo usted mismo usando una simple recursión:
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;
}
FileUtils tiene métodos iterateFiles
y listFiles
. Dales una oportunidad. (de commons-io )
Edición: puede consultar aquí para ver un punto de referencia de diferentes enfoques. Parece que el enfoque de commons-io es lento, así que elija algunos de los más rápidos desde aquí (si es que importa)
Este código está listo para ejecutarse
public static void main(String... args) {
File[] files = new File("D:/").listFiles();
if (files != null)
getFiles(files);
}
public static void getFiles(File[] files) {
for (File file : files) {
if (file.isDirectory()) {
getFiles(file.listFiles());
} else {
System.out.println("File: " + file);
}
}
}
private void fillFilesRecursively(File file, List<File> resultFiles) {
if (file.isFile()) {
resultFiles.add(file);
} else {
for (File child : file.listFiles()) {
fillFilesRecursively(child, resultFiles);
}
}
}