Expresións lambda con ficheiros (Clase Stream)
Sumario
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