Listar archivos en un directorio
Puede enumerar fácilmente los nombres de todos los archivos en un directorio utilizando el método list() de la clase File. Si desea obtener archivos que no sean solo nombres de archivos, puede usar su método listFiles(). Esto es muy simple, lo difícil es cómo procesar la lista devuelta. En lugar de utilizar iteradores externos largos y tradicionales, utilizamos expresiones funcionales elegantes para recorrer esta lista. Aquí también tenemos que usar la nueva interfaz CloseableStream del JDK y algunas funciones relacionadas de alto nivel.
El siguiente código enumera los nombres de todos los archivos en el directorio actual.
Copie el código de código de la siguiente manera:
Archivos.lista(Rutas.get("."))
.forEach(System.out::println);
Si desea enumerar otros directorios, puede reemplazar "." con la ruta completa del directorio al que desea acceder.
Aquí, primero usamos el método get() de Paths para crear una instancia de Path a través de una cadena. Luego obtenemos un objeto ClosableStream a través del método list() de la clase de herramienta Archivos, y podemos usarlo para recorrer todos los archivos en el directorio. Luego usamos el iterador interno forEach() para imprimir el nombre del archivo. Primero veamos algunos de los resultados de salida de este código: enumere los archivos y subdirectorios en el directorio actual.
Copie el código de código de la siguiente manera:
./aArchivosdemuestra.txt
./papelera
./fpij
...
Si solo queremos obtener los subdirectorios del directorio actual, no los archivos, podemos usar el método filter():
Copie el código de código de la siguiente manera:
Archivos.lista(Rutas.get("."))
.filtro(Archivos::isDirectorio)
.forEach(System.out::println);
El método ilter() filtra directorios del flujo de archivos. Pasamos una referencia al método isDirectory de la clase Archivos en lugar de pasar una expresión lambda. Recuerde que el método filter() requiere un tipo de predicado que devuelva un valor booleano, y este método es perfecto. Finalmente usamos un iterador interno para imprimir el nombre del directorio. El programa imprimirá los subdirectorios del directorio actual.
Copie el código de código de la siguiente manera:
./papelera
./fpij
./producción
...
Es mucho más sencillo escribir de esta manera y ahorra una gran cantidad de código en comparación con la antigua forma de escribir en Java. Echemos un vistazo a cómo enumerar archivos que coincidan con un patrón determinado.
Listar archivos especificados en un directorio
Java ha proporcionado durante mucho tiempo una variante del método list() para filtrar nombres de archivos. Esta versión del método list() acepta un parámetro de tipo FilenameFilter. Esta interfaz tiene solo un método aceptar (), que acepta dos parámetros: directorio de archivo (que representa el directorio) y nombre de cadena (que representa el nombre del archivo). Si el método aceptar() devuelve verdadero, el nombre del archivo aparecerá en la lista devuelta; de lo contrario, no aparecerá. Implementemos este método.
El enfoque habitual es pasar una instancia de una clase interna anónima que implementa la interfaz FilenameFilter al método list(). Por ejemplo, veamos cómo usar este método para devolver el archivo .java en el directorio fpij.
Copie el código de código de la siguiente manera:
archivos de cadena final [] =
nuevo archivo("fpij").list(new java.io.FilenameFilter() {
aceptación booleana pública (directorio de archivo final, nombre de cadena final) {
devolver nombre.endsWith(".java");
}
});
System.out.println(archivos);
Realmente requiere algo de tiempo y esfuerzo escribir algunas líneas de código. Este tipo de código es demasiado ruidoso: crear objetos, llamar funciones, definir clases internas anónimas, incrustar métodos en clases, etc. Ya no tenemos que soportar este dolor, simplemente pasar una expresión lambda que acepte dos parámetros y devuelva un bolleano. El compilador de Java se encargará del resto.
El ejemplo anterior podría simplemente reemplazar los elementos internos anónimos con una expresión lambda, pero hay espacio para una mayor optimización. La nueva herramienta DirectoryStream puede ayudarnos a recorrer grandes estructuras de directorios de manera más eficiente. Probemos este método. Esta es una variante del método newDirectoryStream() que acepta un filtro adicional.
Copie el código de código de la siguiente manera:
Archivos.newDirectoryStream(
Paths.get("fpij"), ruta -> ruta.toString().endsWith(".java"))
.forEach(System.out::println);
De esta manera nos deshacemos de la clase interna anónima y hacemos que el código engorroso sea conciso y claro. El resultado de ambas versiones es el mismo. Imprimamos el archivo especificado.
Este código solo generará archivos .java en el directorio especificado. Aquí está parte de su resultado:
Copie el código de código de la siguiente manera:
fpij/Compare.java
fpij/IterateString.java
fpij/ListDirs.java
...
Filtramos archivos según los nombres de los archivos. También se puede filtrar fácilmente por atributos del archivo, como si el archivo es ejecutable, legible, escribible, etc. Para hacer esto, necesita un método listFiles(), que acepte un parámetro de tipo FileFilter. Seguimos usando expresiones lambda en lugar de crear clases internas anónimas. Ahora veamos un ejemplo de cómo enumerar todos los archivos ocultos en el directorio actual.
Copie el código de código de la siguiente manera:
Archivo final[] archivos = nuevo Archivo(".").listFiles(archivo -> archivo.isHidden());
Si estamos operando en un directorio grande, podemos usar DirectoryStream en lugar de llamar directamente al método en Archivo.
La firma de la expresión lambda que pasamos al método listFiles() es la misma que la firma del método Accept() de la interfaz FileFilter. Esta expresión lambda acepta un parámetro de una instancia de Archivo. En este ejemplo, el nombre del parámetro es archivo. Si el archivo tiene atributos ocultos, devuelve verdadero; de lo contrario, devuelve falso.
De hecho, el código se puede simplificar aún más aquí. No pasamos expresiones lambda. Pasar una referencia de método hará que el código parezca más conciso:
Copie el código de código de la siguiente manera:
nuevo archivo(".").listFiles(Archivo::isHidden);
Primero lo implementamos usando expresiones lambda y luego lo refactorizamos para que fuera más conciso usando referencias de métodos. Si escribimos código nuevo, por supuesto deberíamos utilizar este método conciso. Si se pudiera encontrar pronto una implementación tan clara, sin duda daríamos prioridad a su uso. Hay un dicho llamado "primero haz que funcione y luego hazlo mejor". Después de aclararlo, consideraremos la simplicidad y el rendimiento para la optimización.
Usamos un ejemplo para filtrar archivos específicos de un directorio. Echemos un vistazo a cómo recorrer los subdirectorios de un directorio específico.