Acabo de completar los resultados de las pruebas que proporcionan pruebas de rendimiento para muchas de las respuestas. Como era de esperar, todas las respuestas basadas en NIO funcionan mejor. La respuesta commons-io es claramente la de peor desempeño con más del doble de la duración de la carrera.
Brett Ryan
2
Java8: Files.walk?
Benj
Respuestas:
327
Java 8 proporciona una buena secuencia para procesar todos los archivos en un árbol.
Esto proporciona una forma natural de atravesar archivos. Dado que es una secuencia, puede realizar todas las operaciones de secuencia agradables en el resultado, como límite, agrupación, asignación, salida anticipada, 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.
Tenga en cuenta que si bien JavaDoc elude que este método podría ser más eficiente que Files.walk , es efectivamente idéntico, la diferencia en el rendimiento se puede observar si también está recuperando atributos de archivo dentro de su filtro. Al final, si necesita filtrar los atributos, use Files.find , de lo contrario use Files.walk , principalmente porque hay sobrecargas y es más conveniente.
Uno de esos ejemplos que puede mostrar la magia de la programación funcional incluso para los principiantes.
Johnny
2
¿Cómo se compara el rendimiento de esto con los métodos anteriores a Java 8? Mi recorrido actual del directorio es demasiado lento y estoy buscando algo que lo acelere.
Sridhar Sarnobat
1
Estoy escribiendo algunas pruebas que contienen la mayoría de las variantes en las respuestas proporcionadas. Hasta ahora, parece que usar Files.walkcon un flujo paralelo es el mejor, seguido de cerca por lo Files.walkFileTreecual es solo un poco más lento. La respuesta aceptada usando commons-io es, con mucho, la más lenta, según mis pruebas, 4 veces más lenta.
Brett Ryan
1
@BrettRyan, probé tu solución pero recibo una excepción Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException. ¿Cómo podría corregirlo
Editar: puede consultar aquí para obtener un punto de referencia de diferentes enfoques. Parece que el enfoque commons-io es lento, así que elija algunos de los más rápidos desde aquí (si es importante)
FYI / TLDR: si solo desea enumerar todos los archivos de forma recursiva sin filtrado, haga FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE), donde dirhay un objeto File que apunta al directorio base.
andronikus
2
Es posible que desee considerar el uso listFilesAndDirs(), ya listFiles()que no devuelve carpetas vacías.
schnatterer
1
@MikeFHay Mirando el código FileUtils, creo que debería serlo FileUtils.listFiles(dir, true, true). utilizando FileUtils.listFiles(dir, null, true)arrojará una excepción, mientras FileUtils.listFiles(dir, true, null)que enumerará todos los archivos sin buscar en subdirectorios.
ocramot
¿Qué tal una biblioteca nativa JDK? Puedo implementar esto fácilmente, pero simplemente sería C&P de otros lugares
Christian Bongiorno
1
Estoy poniendo algunas pruebas juntas, pero hasta ahora parece funcionar 4 veces más lento que el uso de alternativas JDK8 o JDK7. Los enlaces simbólicos también resultan problemáticos con este enfoque, especialmente cuando se vinculan a directorios más altos en el árbol, esto hace que el método nunca regrese, esto puede evitarse manejando el filtro, pero desafortunadamente los enlaces simbólicos en sí mismos no son visitados incluso un archivo.
Brett Ryan
138
// Listo para correr
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:\\");}}
Solo tenga en cuenta que para los enlaces simbólicos que apuntan a una ruta más alta en la jerarquía de la ruta, el método nunca terminará. Considere una ruta con un enlace simbólico que apunta a -> ..
Brett Ryan
2
Esto es esencialmente una mala implementación de Files.walkFileTree. Recomendaría que la gente mire FIles.walkFileTree en lugar de intentar rodarlo usted mismo ... Tiene un manejo para el problema exacto @BrettRyan lo señaló.
Tyler Nichols
Gracias por incluir import java.io.File ;. Muchos ejemplos se olvidan de incluir el espacio de nombres o incluso el tipo de datos, lo que hace que el ejemplo sea un punto de partida en un viaje de descubrimiento. Aquí este ejemplo está listo para ejecutarse. Gracias.
barrypicker
La ruta puede variar dependiendo de dónde esté el archivo Filewalker. Uso "/", "./"o "../"para el directorio raíz, el directorio de trabajo actual y el directorio principal, respectivamente
Si proporciona un punto de partida y un visitante de archivos, invocará varios métodos en el visitante de archivos mientras recorre el archivo en el árbol de archivos. Esperamos que las personas usen 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.
publicvoid list(File file){System.out.println(file.getName());File[] children = file.listFiles();for(File child : children){
list(child);}}
System.out.println está ahí para indicar que debe hacer algo con el archivo. no es necesario diferenciar entre archivos y directorios, ya que un archivo normal simplemente tendrá cero hijos.
¡Por favor! deje que la persona que llama inicialice la lista de archivos para que no tenga que verificar su nulidad cada vez. Si desea crear un segundo método (público) que cree la lista, llame a este método interno y devuelva la lista completa.
helios
1
lo que sea. un cheque nulo no es muy costoso, aparte de la conveniencia + preferencia personal, creo que entenderá el punto.
pstanton
¿Puedes explicar un poco más verbosamente?
uday
8
Creo que esto debería hacer el trabajo:
File dir =newFile(dirname);String[] files = dir.list();
De esta manera tienes archivos y directorios. Ahora use la recursión y haga lo mismo para los directorios (la Fileclase tiene isDirectory()método).
Además del recorrido recursivo, también se puede utilizar un enfoque basado en el visitante.
El siguiente código utiliza el enfoque basado en el visitante para el recorrido. Se espera que la entrada al programa sea el directorio raíz para atravesar.
La respuesta aceptada es excelente, sin embargo, se descompone cuando quieres hacer IO dentro de la lambda.
Esto es lo que puede hacer si su acción declara IOExceptions.
Puede tratar la secuencia filtrada como un Iterable, y luego realizar su acción en un ciclo regular para cada ciclo. De esta manera, no tiene que manejar excepciones dentro de una lambda.
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);}}
Publicando este ejemplo, ya que tuve problemas para entender cómo pasar el parámetro del nombre de archivo en el ejemplo # 1 dado por Bryan, usando foreach en Stream-result -
Producirá una lista de texto de todos los archivos que no son de directorio bajo una raíz determinada, un archivo por línea con la ruta relativa a la raíz y la longitud.
Basado en la respuesta del apilador. Aquí hay una solución que funciona en JSP sin bibliotecas externas para que pueda colocarla 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"%><%!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()+"/";%>
Si bien probablemente funcione, la pregunta es sobre la exploración de archivos, no sobre la representación de archivos examinados. Exponga mejor su algoritmo como tal, no es una práctica recomendada incorporar lógica de negocios dentro de un JSP.
Samuel Kerrien
Eso depende de lo que estés haciendo. En una aplicación de tamaño empresarial, tiene toda la razón. Si solo necesita esto como un complemento a una lista simple e independiente, entonces esto está perfectamente bien.
Respuestas:
Java 8 proporciona una buena secuencia para procesar todos los archivos en un árbol.
Esto proporciona una forma natural de atravesar archivos. Dado que es una secuencia, puede realizar todas las operaciones de secuencia agradables en el resultado, como límite, agrupación, asignación, salida anticipada, 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.
Tenga en cuenta que si bien JavaDoc elude que este método podría ser más eficiente que Files.walk , es efectivamente idéntico, la diferencia en el rendimiento se puede observar si también está recuperando atributos de archivo dentro de su filtro. Al final, si necesita filtrar los 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 .
fuente
Files.walk
con un flujo paralelo es el mejor, seguido de cerca por loFiles.walkFileTree
cual es solo un poco más lento. La respuesta aceptada usando commons-io es, con mucho, la más lenta, según mis pruebas, 4 veces más lenta.Exception in thread "main" java.io.UncheckedIOException: java.nio.file.AccessDeniedException
. ¿Cómo podría corregirloFileUtils tiene
iterateFiles
ylistFiles
métodos. Pruébalos (de commons-io )Editar: puede consultar aquí para obtener un punto de referencia de diferentes enfoques. Parece que el enfoque commons-io es lento, así que elija algunos de los más rápidos desde aquí (si es importante)
fuente
FileUtils.listFiles(dir, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)
, dondedir
hay un objeto File que apunta al directorio base.listFilesAndDirs()
, yalistFiles()
que no devuelve carpetas vacías.FileUtils.listFiles(dir, true, true)
. utilizandoFileUtils.listFiles(dir, null, true)
arrojará una excepción, mientrasFileUtils.listFiles(dir, true, null)
que enumerará todos los archivos sin buscar en subdirectorios.// Listo para correr
fuente
-> .
."/"
,"./"
o"../"
para el directorio raíz, el directorio de trabajo actual y el directorio principal, respectivamenteJava 7
tendrátiene Files.walkFileTree :Ahora hay un tutorial Oracle sobre esta pregunta .
fuente
No se necesitan bibliotecas externas.
Devuelve una Colección para que pueda hacer lo que quiera después de la llamada.
fuente
Yo iría con algo como:
System.out.println está ahí para indicar que debe hacer algo con el archivo. no es necesario diferenciar entre archivos y directorios, ya que un archivo normal simplemente tendrá cero hijos.
fuente
listFiles()
: "Si este nombre de ruta abstracto no denota un directorio, entonces este método regresanull
".Prefiero usar una cola sobre la recursividad para este tipo de conversión simple:
fuente
solo escríbelo tú mismo usando una recursión simple:
fuente
Creo que esto debería hacer el trabajo:
De esta manera tienes archivos y directorios. Ahora use la recursión y haga lo mismo para los directorios (la
File
clase tieneisDirectory()
método).fuente
Con Java 7 puede usar la siguiente clase:
fuente
En Java 8, ahora podemos usar la utilidad Archivos para recorrer un árbol de archivos. Muy simple.
fuente
Este código está listo para ejecutarse
fuente
Además del recorrido recursivo, también se puede utilizar un enfoque basado en el visitante.
El siguiente código utiliza el enfoque basado en el visitante para el recorrido. Se espera que la entrada al programa sea el directorio raíz para atravesar.
fuente
Puede usar el siguiente código para obtener una lista de archivos de carpetas o directorios específicos de forma recursiva.
fuente
La respuesta aceptada es excelente, sin embargo, se descompone cuando quieres hacer IO dentro de la lambda.
Esto es lo que puede hacer si su acción declara IOExceptions.
Puede tratar la secuencia filtrada como un
Iterable
, y luego realizar su acción en un ciclo regular para cada ciclo. De esta manera, no tiene que manejar excepciones dentro de una lambda.Encontré ese truco aquí: https://stackoverflow.com/a/32668807/1207791
fuente
BFS no recursivo con una sola lista (un ejemplo particular es buscar archivos * .eml):
fuente
Mi versión (por supuesto, podría haber utilizado el paseo incorporado en Java 8 ;-)):
fuente
Aquí una solución simple pero que funciona perfectamente usando
recursion
:fuente
fuente
Se me ocurrió esto para imprimir todos los archivos / nombres de archivo de forma recursiva.
fuente
El ejemplo genera archivos * .csv en subdirectorios de búsqueda recursiva de directorios usando Files.find () de java.nio:
Publicando este ejemplo, ya que tuve problemas para entender cómo pasar el parámetro del nombre de archivo en el ejemplo # 1 dado por Bryan, usando foreach en Stream-result -
Espero que esto ayude.
fuente
Kotlin tiene
FileTreeWalk
para este propósito. Por ejemplo:Producirá una lista de texto de todos los archivos que no son de directorio bajo una raíz determinada, un archivo por línea con la ruta relativa a la raíz y la longitud.
fuente
Otra forma de hacerlo, incluso si alguien ya proporciona caminar Java 8.
Este te proporcionará todos los archivos de forma recursiva
fuente
Basado en la respuesta del apilador. Aquí hay una solución que funciona en JSP sin bibliotecas externas para que pueda colocarla en casi cualquier lugar de su servidor:
Entonces solo haces algo como:
fuente