java-8 - productividad - medicion del rendimiento portuario
¿Las operaciones de la terminal cierran la corriente? (2)
dirPath
contiene 200k archivos. Quiero leerlos uno por uno y procesarlos. El siguiente fragmento provoca java.nio.file.FileSystemException: dirPath/file-N Too many open files
. ¿No se supone que la operación del terminal para forEach()
cierra la secuencia abierta (es decir, el archivo abierto) antes de pasar al siguiente? En otras palabras, ¿tengo que agregar try-with-resources para los archivos transmitidos?
Files.list(dirPath)
.forEach(filePath -> {
Files.lines(filePath).forEach() { ... }
});
Un anidado para forEach
es la herramienta incorrecta, en la mayoría de los casos.
El código
Files.list(dirPath).forEach(filePath -> Files.lines(filePath).forEach(line -> { ... });
puede y debe ser reemplazado por
Files.list(dirPath).flatMap(filePath -> Files.lines(filePath)).forEach(line -> { ... });
o bueno, ya que no es tan fácil en este caso:
Files.list(dirPath).flatMap(filePath -> {
try { return Files.lines(filePath);}
catch(IOException ex) { throw new UncheckedIOException(ex); }
}).forEach(line -> { });
como efecto secundario, obtienes lo siguiente gratis:
Stream.flatMap(…)
:
Cada flujo mapeado se cierra después de que su contenido se haya colocado en esta secuencia.
Entonces esa es la solución preferida. O bueno, para hacerlo completamente correcto:
try(Stream<Path> dirStream = Files.list(dirPath)) {
dirStream.flatMap(filePath -> {
try { return Files.lines(filePath);}
catch(IOException ex) { throw new UncheckedIOException(ex); }
}).forEach(line -> { });
}
No forEach
no cierra la secuencia (creada por Files.list
o Files.lines
). Está documentado en javadoc, por ejemplo para Files.list
:
La secuencia devuelta encapsula un Reader. Si se requiere la eliminación oportuna de los recursos del sistema de archivos, se debe utilizar la construcción try-with-resources para garantizar que el método de cierre de la secuencia se invoque después de que se completen las operaciones de la secuencia.