Contenido del curso

Construcción de clases y modelado de objetos

Leer archivos planos con Java nio

Resumen

Leer archivos planos en Java es una de las habilidades base que necesitas como desarrollador para que tus aplicaciones recuperen información incluso después de reiniciarse. Aquí aprenderás a transformar líneas de texto en objetos usando Files, Paths y un manejo limpio de excepciones, aplicado al caso de Platzi Play y su catálogo de películas.

¿Cómo se estructura un archivo plano para almacenar objetos?

Antes de tocar código, necesitas un archivo de texto bien formado que represente cada objeto como una línea con campos separados por un carácter consistente.

En la raíz del proyecto, hermano de src y de .gitignore, se crea un archivo llamado contenido.txt. Cada línea representa una película y los campos van separados por un pipe (|): título, duración, categoría, calificación y fecha de estreno [01:00].

¿Por qué usar pipe como separador en archivos planos? Porque es un carácter poco común dentro de títulos o textos, lo que reduce el riesgo de partir mal una línea. Comas o puntos suelen aparecer en los datos y rompen el parseo.

Un detalle interesante: algunas películas como Shrek no tienen calificación, así que su campo queda vacío y aparece un doble separador ||. Eso es válido y tu código debe contemplarlo.

¿Cómo leer un archivo plano línea por línea en Java?

Java ofrece desde el paquete java.nio.file dos clases que hacen esta tarea muy sencilla: Files y Paths.

El método Files.readAllLines retorna una List<String> con cada línea del archivo. Para indicarle la ruta usas Paths.get("contenido.txt"). El resultado es una lista que puedes recorrer con un forEach.

java try { List<String> lineas = Files.readAllLines(Paths.get("contenido.txt")); lineas.forEach(linea -> System.out.println(linea)); } catch (IOException e) { System.out.println("Ocurrió un error leyendo el archivo: " + e.getMessage()); }

¿Por qué Java obliga a manejar IOException al leer archivos?

Porque IOException es una checked exception: representa errores previsibles, como que el archivo no exista o no se pueda abrir, y Java te fuerza a controlarlos con try/catch o declarándolos con throws [02:30].

Envolver la lectura en un bloque try/catch te permite mostrar un mensaje útil al usuario en lugar de que la aplicación se caiga sin explicación.

¿Cómo convertir cada línea de texto en un objeto Película?

Leer las líneas es solo el primer paso. Lo valioso es transformar ese texto plano en objetos que tu aplicación pueda usar.

Dentro del forEach, cada línea se parte usando split con la expresión regular \\|. El doble backslash es necesario para escapar el carácter especial pipe en regex. El resultado es un arreglo de strings llamado datos.

java String[] datos = linea.split("\|"); if (datos.length == 5) { String titulo = datos[0]; int duracion = Integer.parseInt(datos[1]); Genero genero = Genero.valueOf(datos[2].toUpperCase()); double calificacion = datos[3].isBlank() ? 0 : Double.parseDouble(datos[3]); LocalDate fechaEstreno = LocalDate.parse(datos[4]); }

Aquí ocurren varias cosas importantes:

  • La validación datos.length == 5 descarta líneas mal formadas.
  • Integer.parseInt y Double.parseDouble convierten texto a tipos numéricos.
  • Genero.valueOf mapea el texto a un valor del enum, por eso se pasa a mayúsculas.
  • LocalDate.parse convierte el texto en un objeto de fecha sin librerías externas.

¿Cuál es la diferencia entre isBlank e isEmpty en Java? isEmpty solo verifica si el string tiene longitud cero. isBlank además detecta cadenas que solo contienen espacios en blanco, lo que lo hace más seguro para validar datos sucios.

La expresión datos[3].isBlank() ? 0 : Double.parseDouble(datos[3]) es un operador ternario: una forma compacta de escribir un if/else dentro de una asignación.

¿Cómo organizar la lectura de archivos siguiendo buenas prácticas?

Tener todo este código dentro del main funciona, pero ensucia tu clase principal. La buena práctica es centralizarlo en una clase de utilidades.

Dentro del paquete util se crea una clase FileUtils con un método estático leerContenido que retorna una List<Pelicula>. También se extraen dos constantes para evitar valores mágicos en el código:

  • NOMBRE_ARCHIVO con el valor "contenido.txt".
  • SEPARADOR con el valor "\\|".

java public static List<Pelicula> leerContenido() { List<Pelicula> contenidoDesdeArchivo = new ArrayList<>(); try { List<String> lineas = Files.readAllLines(Paths.get(NOMBRE_ARCHIVO)); // parseo y add a la lista } catch (IOException e) { System.out.println("Error: " + e.getMessage()); } return contenidoDesdeArchivo; }

En el main, cargar las películas se reduce a una sola línea: plataforma.getContenido().addAll(FileUtils.leerContenido()). El método addAll recibe una colección completa y la integra a la lista existente.

¿Qué ganas al persistir datos en archivos planos?

La aplicación recupera su estado al iniciar. Si reordenas las líneas en contenido.txt y pones Titanic primero, al ejecutar la opción de mostrar todo, Titanic aparece de primero. Eso confirma que los datos vienen del archivo y no de un hardcode en el código fuente.

Este mismo patrón te sirve para catálogos, configuraciones, logs o cualquier información que necesites mantener entre ejecuciones. ¿Qué archivo plano vas a leer en tu próximo proyecto? Cuéntalo en los comentarios.