Java NIO

por


Publicado en: abril 6, 2018



En este artículo explicaremos como recorrer una estructura de directorios por medio de NIO y Streams.

Java NIO

En Java 7 se introdujo el NIO.2 (nonblocking input/output) y ahi se agregan nuevas clases para la manipulación de archivos y directorios. Además se mejoraron para permitir el uso de Streams; en este aspecto sólo debemos recordarles que -por ejemplo- la interface jav.nio.file.DirectoryStream no tiene nada que ver con los streams funcionales. El nombre tiende a la confusión; y esperamos que eventualmente Java reorganice el nombre de estas clases.

Utilización


Supongamos que como parte de un proyecto, se les encomienda la tarea de recorrer una estructura de directorios; como ilustración: directorios con archivos que deben procesarse, o XML para ser enviados a una cola, etc.

En Java 8 y subsiguientes; eso se puede lograr por medio del método Files.walk. Este método tiene como firma lo siguiente:

   public static Stream<Path> walk(Path start, FileVisitOption... options) throws IOException

Los argumentos corresponden al Path de inicio y una lista de argumentos del tipo FileVisitOption. El tipo que retorna es un Stream lazy de instancias de Path obtenidas al recorrer el sistema de archivos iniciando en el punto de origen indicado.

Por ejemplo, el código que mostramos seguidamente recorre todo los archivos a partir de un punto de inicio e imprime su ruta y nombre completo.

  try (Stream<Path> paths = Files.walk(Paths.get("/opt/demos")))  {
         paths.forEach(System.out::println);
     }

Observen que no enviamos ningún argumento adicional al método walk. El resultado tiene la garantía que regresa al menos un elemento; que sería el argumento o path de inicio. Conforme cada path es localizado, el sistema determina si es un directorio; y si lo es, lo recorre antes de continuar. Es decir, hace un recorrido por profundidad primero.

En ocasiones, no es deseable o necesario recorrer toda la estructura de directorios; pues nos interesa sólo un nivel de profundidad. Para ellos podemos hacer uso del método walk de la siguiente manera:

  try (Stream<Path> paths = Files.walk(Paths.get("/opt/demos"), 1))  {
         paths.forEach(System.out::println);
     }

En ese código, únicamente bajamos un nivel en la estructura de directorios. Si colocamos el valor 0; es equivalente a decir que nos quedamos al nivel del path de inicio.

Por último, puede ser necesario que te interesen solo archivos con ciertos atributos. Para ello se tiene el método find que permite lograr lo anterior; como mostramos de seguido.

try (Stream<Path> paths = Files.find(Paths.get("/opt/demos"),
               Integer.MAX_VALUE,
               (path, attributes)
               -> !attributes.isDirectory() && path.toString().contains("java"))) {
           paths.forEach(System.out::println);
       }

En este ejemplo; indicamos el path de inicio; el Integer.MAX_VALUE es el nivel de profundidad que equivale a recorrer todo y luego un BiPredicate para determinar si un Path determinado debe ser retornado o no. En este caso, se omiten directorios y deben ser archivos que contengan la palabra java en alguna parte. Es importante tomar en cuenta que el BiPredicate debe retornar un valor booleano.

Conclusión

Esperamos que con este artículo les invite a investigar sobre Java NIO2 en sus desarrollos.

Autor del Artículo

Gerardo Arroyo Arce

Gerardo Arroyo Arce

Chief Technology Officer.

  • Ingeniero en Software. ITCR.
  • Master en Computación en Informática. UCR.
  • AWS Certified Solutions Architect - Associate
  • Oracle Certified Expert, JEE 6 Web Services Developer.
  • Oracle Certified Professional, Java SE 7 Programmer.
  • Oracle WebLogic Server 12c Certified Implementation Specialist.