Expresións lambda con ficheiros (Clase Stream)

De MediaWiki
Revisión del 15:21 28 feb 2022 de Joselv (discusión | contribuciones) (Página creada con «= Lambda con Ficheiros = En cada nova versión de Java amplíase o uso de lambda e expresións de programación funcional: actualizanse así as posibilidades de Java para s…»)
(dif) ← Revisión anterior | Revisión actual (dif) | Revisión siguiente → (dif)
Ir a la navegación Ir a la búsqueda

Lambda con Ficheiros

En cada nova versión de Java amplíase o uso de lambda e expresións de programación funcional: actualizanse así as posibilidades de Java para ser unha linguaxe máis directa e menos “verbosa”: resumindo, menos liñas de programación para acadar o mesmo.

Coa API java.NIO temos a clase Files, que se pode utilizar con expresións lambda. A clase Files xunto coa clase Stream crean un binomio moi últil para operacións con ficheiros.

Ler un ficheiro de maneira secuencial:

Path file = Paths.get("readFile.txt");

       try(Stream<String>lines = Files.lines(file)
                       .onClose(() -> System.out.println("Fin de lectura"))) {
           lines.forEach(System.out::println);
       }

Unha vez que se obten a ruta do ficheiro utilizamos a método estático lines() de Files. Este método devolvenos un fluxo de traballo (Stream), que ten unha directiva cando se pecha o fluxo (onClose) e un método para percorrer todas as liñas (forEach). A clase Stream pódese “alimentar” de moitas formas: se pretendemos unha maior eficiencia un obxecto BufferedReader debe ser o elexido. Files ten un método no que se obten un buffer de lectura (newBufferedReader):

try(BufferedReader br = Files.newBufferedReader(file);

           Stream<String> lines = br.lines()
                   .onClose(() -> System.out.println("Fin de lectura de ficheiro."));){
           
           lines.forEach(System.out::println);
       }

Ler con procesamento pararelo

Outra opción que nos ofrece Stream e onde non nos ten que importar o tratamento secuencial do ficheiro é o predicado parallel(). O que fai esta opción é crear fios de execución sobre o contido do Stream (neste caso o ficheiro), mellorando o rendemento:

try(Stream<String>lines = Files.lines(file)

                       .parallel()
                       .onClose(() -> System.out.println("Fin de lectura de ficheiro."))) {
           
           //modificamos esta parte para poder observar os fíos que se xeneran
            lines.forEach(s ->{
                   System.out.println(s +" " + Thread.currentThread().getName());});

Exemplo -> LerFicheiroLambda.java

Lectura condicional:

Stream ten un predicado que é filter(): permitenos filtrar qué liñas nos interesa do ficheiro. Ten múltiples opcións; a continuación amosamos un exemplo sinxelo:

try (Stream<String> lines = Files.lines(Path.of("probas.txt"))) {

           long i = lines.filter(line -> line.startsWith("T"))
           .count();

Filter necesita un predicado lóxico booleano, ou utilizar métodos de Stream coma os seguintes: contentEquals(String st) endsWith(String sufix) startsWith(String prefix) matches(String red): expresións regulares. … Exemplos→ LerFilter.java


Uso de lambda para operacións de directorios e arquivos de sistema

Para listar os directorios dunha ruta, temos a directiva isDirectory de Files:

try (Stream<Path> paths = Files.list(Path.of(folderPath))) {

 	 paths.filter(Files::isDirectory)
   	.forEach(System.out::println);

} Fíxate que devolve un Stream de path é decir rutas de ficheiros.

Para listar os ficheiros dunha ruta:

try (Stream<Path> paths = Files.list(Path.of(folderPath))) {

   paths.filter(Files::isRegularFile)
   .forEach(System.out::println);

}

Para percorrer todo a árbore de directorios: PENDIENTE

Coma se fora de xeito recursivo Files ten un método estático chamado walk() que devolve un stream con todos os elementos da carpeta, das subcarpetas etc. ata chegar a final da árbore. O stream estará formado por todos os camiños que forma esa árbore:

Stream<Path> miStream = Files.walk(Paths.get("./src"));

    miStream.forEach(System.out::println);


Búsqueda de ficheiros

A clase Files ten un método de búsqueda de ficheiros. O uso máis frecuente é con tres argumentos de entrada: Path p: obxecto que representa a ruta onde se vai buscar. int maxDepth: enteiro que representa que nivel de búsqueda se precisa na árbore de directorios. Se indicamos Integer.Maxvalue sería ata o final da árbore de ficheiros, se indicamos “1” sería o primeiro nivel. BiPredicate <Path, BasicFileAttributes> matcher: é unha interfaz funcional que serve para indicar as condicións de búsqueda.

try (Stream<Path> pathStream = Files.find(path, Integer.MAX_VALUE,

               (p, basicFileAttributes) ->
                       p.getFileName().toString().equalsIgnoreCase(fileName))

Exemplos → BusquedaFicheiroLambda.java

Actividade pasar información dun ficheiro csv a obxectos: Igual es mucho y no lo incluyo. Como actividad de ampliación? Vamos viendo!

Exercicios para practicar

Exercicio 1 - Búsqueda de ficheiros

Crea un método de búsqueda de ficheiros con Files.find a partires dunha ruta cun determinado tamaño (Files.size) usando expresións lambda. Mellora o teu programa detectando se un ficheiro é un directorio (Files.isDirectory), e devolvendo falso. Solucion: BusquedaFicheirosTamano.java

Exercicio 2 - Búsqueda de ficheiros recursiva

Crea un método que busque un ficheiro nun directorio e en todas as suas subcarpetas (ata o final da árbore de directorios) usando lambda. Para ser máis eficiencia usa un filtro con Files::isRegularFile. Solución: BusquedaWalkFicheiro.java