Java NIO.2 a través de ejemplos

En la versión 7 de Java se introdujo el paquete java.nio.file, el cual supuso una importante mejora respecto al antiguo manejo de ficheros vía IO. Operaciones aparentemente tan sencillas como leer/escribir un archivo de texto en/desde un String suponían la escritura de varias líneas de código. De hecho, una librería prácticamente obligatoria cuando se tenía que hacer un uso importante de ficheros era Commons IO.

Se mostrarán a continuación varios ejemplos típicos de uso, donde se verá la potencia y sencillez de este paquete.

Crea un fichero vacío si aún no existe

Path emptyFile = Paths.get("/examples/emptyFile.txt");
if (Files.notExists(emptyFile)) {
	emptyFile = Files.createFile(Paths.get("/examples/emptyFile.txt"));
}

Lee el contenido de un fichero de texto a una cadena

String content = new String(Files.readAllBytes(Paths.get("/examples/sampleText.txt")),
		StandardCharsets.UTF_8);
System.out.println(content);

Lee el contenido de un fichero de texto línea a línea

List<String> lines = Files.readAllLines(Paths.get("/examples/sampleText.txt"),
		StandardCharsets.UTF_8);
for (String line : lines) {
	System.out.println(line);
}

Escribe un String a un fichero de texto, sobreescribiéndolo si ya existiera

String text = "Esto es una cadena de prueba";
Files.write(Paths.get("/examples/writeText.txt"), text.getBytes(StandardCharsets.UTF_8),
		StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

Escribe una lista de String a un fichero de texto, sobreescribiéndolo si ya existiera

List<String> textLines = Arrays.asList("Línea 1", "Línea 2", "Línea 3");
Files.write(Paths.get("/examples/writeLines.txt"), textLines, StandardCharsets.UTF_8,
		StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);

Crear una estructura de directorios de forma recursiva. Si algún directorio ya existiera no lanzará excepción

Files.createDirectories(Paths.get("/examples/level1/level2/level3"));

Tamaño en bytes de un directorio

long size = Files.walk(Paths.get("/examples")).parallel().filter(p -> p.toFile().isFile())
		.mapToLong(p -> p.toFile().length()).sum();
System.out.println("Tamaño del directorio: " + size);

Cuenta el número de ficheros de un directorio de forma recursiva

long count = Files.walk(Paths.get("/examples")).parallel().filter(p -> !p.toFile().isDirectory()).count();
System.out.println("Total de ficheros: " + count);

Cuenta el número de ficheros no vacíos con ciertas extensiones leyendo solo dos niveles a partir del directorio principal

long parcialCount = Files.walk(Paths.get("/examples"), 2).parallel()
		.filter(p -> p.toString().matches("(?i).+\\.(txt|log|conf)$") && p.toFile().length() > 0L).count();
System.out.println("Ficheros que cumplen con el filtro: " + parcialCount);

Lista recursiva con los directorios contenidos en un directorio padre

List<Path> dirs = Files.walk(Paths.get("/examples")).filter(Files::isDirectory).map(x -> x.toAbsolutePath())
		.collect(Collectors.toList());
for (Path dir : dirs) {
	System.out.println("Ruta del directorio: ".concat(dir.toString()));
}

Lista recursiva con los ficheros contenidos en un directorio

List<Path> files = Files.walk(Paths.get("/examples"))
		.filter(Files::isRegularFile).map(x -> x.toAbsolutePath()).collect(Collectors.toList());
for (Path file : files) {
	System.out.println("Ruta del fichero: ".concat(file.toString()));
}

Limpia el contenido de un directorio borrando de forma recursiva todos los ficheros contenidos en el mismo

Files.walk(Paths.get("/to_be_cleared")).parallel().filter(p -> p.toFile().isFile()).forEach(File::delete);

Borra de forma recursiva un directorio y todo su contenido

Files.walk(Paths.get("/to_be_deleted")).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);

Copia un directorio con todo su contenido desde un origen a un destino

Path from = Paths.get("/examples/source_dir");
Path dest = Paths.get("/examples/dest_dir");
try (Stream<Path> stream = Files.walk(from)) {
	stream.forEachOrdered(source -> {
		try {
			Files.copy(source, dest.resolve(from.relativize(source)), StandardCopyOption.REPLACE_EXISTING);
		} catch (IOException e) {
			e.printStackTrace();
		}
	});
}

Mueve un directorio con todo su contenido

Files.move(Paths.get("/examples/source_dir"), Paths.get("/examples/dest_dir"),
		StandardCopyOption.REPLACE_EXISTING);

Convierte de Path a File y de File a Path

File file = onePath.toFile();
Path path = oneFile.toPath();

Como se ha podido comprobar, el uso de esta nueva API permite navegar, leer y escribir ficheros, consultar sus atributos (fechas de creación, modificación, acceso, permisos…) copiar y mover ficheros o directorios, reconocer enlaces simbólicos, entrada/salida asíncrona y más funcionalidades que nos facilitarán enormemente el trabajo con ficheros y directorios sin falta de importar librerías externas.

VIERNES 21 DE AGOSTO DE 2020