Ficheros y directorios
2. Gestión de ficheros y directorios
La gestión de ficheros y directorios se realiza a través de Path y Files.
- Path: Representa una ruta en el sistema de ficheros (ej.
/home/usuario/foto.pngoC:\usuarios\docs\informe.txt). Un objeto Path es una dirección y no significa que el fichero o directorio exista.
Métodos principales de Path
| Método | Descripción |
|---|---|
Path.of(String) |
Crea un objeto Path a partir de un String de ruta (Java 11+). Por debajo llama a Paths.get() que es el método original de la clase Paths (Java 7+). |
toString() |
Devuelve la ruta como un String (se llama por defecto desde println). |
toAbsolutePath() |
Devuelve la ruta absoluta del Path. |
fileName() |
Devuelve el nombre del fichero o directorio final de la ruta. |
Ejemplo 1
🔍 Ejecutar y Analizar
Ejecuta el ejemplo anterior y comprueba que la salida es la siguiente:
- Files: Es una clase de utilidad con las acciones (borrar, copiar, mover, leer, etc) que podemos realizar sobre las rutas (
Path).
Métodos principales de Files
| Método | Descripción |
|---|---|
exists(), isDirectory(), isRegularFile(), isReadable() |
Verificar de existencia y accesibilidad. |
list(), walk() |
Listar contenido de un directorio. |
readAttributes() |
Obtener atributos (tamaño, fecha, etc.). |
createDirectory() |
Crear un directorio: Solo crea el directorio y espera que todo el "camino" hasta él ya exista. |
createDirectories |
Crea un directorio y también los directorios padre si no existen. Es la forma más segura. |
createFile() |
Crear un fichero. |
delete() |
Borrar un fichero o directorio (lanza una excepción si el borrado falla). Lanza la excepción NoSuchFileException si el fichero o directorio no existe. Es más seguro deleteIfExists(). |
move(origen, destino) |
Mover o renombrar un fichero o directorio. |
copy(origen, destino) |
Copiar un fichero o directorio. Si el destino ya existe se puede sobreescribir utilizando copy(Path, Path, REPLACE_EXISTING). Si se copia un directorio no se copiará su contenido, el nuevo directorio estará vacío. |
Ejemplo 2
El siguiente ejemplo es un organizador de ficheros. Imagina una carpeta de "multimedia" donde todo está desordenado. El programa organizará los ficheros en subcarpetas según su extensión (.pdf, .jpg, .mp3, etc).
🔍 Ejecutar y Analizar
Crea una carpeta, dentro de tu proyecto llamada multimedia y guarda diferentes archivos (pdf, jpg, txt, etc.). Ejecuta el ejemplo anterior y comprueba que la salida es parecida a la siguiente.
En el ejemplo anterior hemos recorrido un directorio para organizar los ficheros que contenía. Recorrer un directorio para "mirar" su contenido es útil en muchas situaciones y hay varias formas de hacerlo. A continuación veremos algunas:
Files.list(path): Es la utilizada en el ejemplo anterior. Lista únicamente el contenido de un directorio sin acceder a las subcarpetas. Será útil cuando solamente sea necesario acceder al contenido directo de una carpeta, por ejemplo para organizar ficheros en un directorio, mostrar el contenido de la carpeta actual o buscar un fichero específico solo en este nivel.- Ventajas:
- Rápido y eficiente al no ser recursivo.
- Ofrece un control preciso, operando solo en el primer nivel del directorio.
- Devuelve un
Streamde Java que permite usar operadores funcionales (filter,map, etc.) de forma segura con.use.
- Inconvenientes:
- No explora subdirectorios.
- Para recorrer un árbol completo, se necesita implementar lógica recursiva manualmente.
- Ventajas:
Files.walk(path): Recorre un directorio y todo su contenido recursivamente. Entra en cada subcarpeta, y en sus subcarpetas hasta el final. Será útil para operar sobre un directorio y todo lo que contiene, sin importar la profundidad, por ejemplo para buscar un fichero por nombre en cualquier subcarpeta, eliminar todos los ficheros temporales de un proyecto o contar todos los ficheros .kt de un repositorio.- Ventajas:
- Recorre árboles de directorios completos (recursivo) de forma muy sencilla.
- Extremadamente potente para búsquedas profundas o aplicar operaciones a todos los elementos anidados.
- También devuelve un
Stream, permitiendo un filtrado y procesamiento muy expresivo.
- Inconvenientes:
- Puede ser lento y consumir más memoria en directorios con miles de ficheros.
- Es una herramienta excesiva ('overkill') para tareas que solo requieren acceder al nivel actual.
- Ventajas:
Files.newDirectoryStream(path): Es similar aFiles.list(), listando solo el contenido inmediato. La diferencia es que no devuelve unStreamde Java 8 (que permite usar.filter,.forEach, etc.), sino unDirectoryStream, que es una versión más antigua que se usa con bucles for. Es menos común en código Kotlin moderno, pero es bueno reconocerlo para poder entender en proyectos antiguos (legacy). Para cualquier tarea nueva,Files.list()yFiles.walk()son superiores en seguridad y expresividad.- Ventajas:
- Utiliza un bucle
for-eachtradicional, que puede resultar familiar.
- Utiliza un bucle
- Inconvenientes:
- ¡PELIGRO! Requiere cerrar el recurso manualmente (
.close()). Si se olvida, provoca fugas de recursos (resource leaks). - Es menos expresivo que los Streams. No se pueden encadenar operadores funcionales fácilmente.
- Considerado obsoleto en código Kotlin idiomático, que prefiere
Files.list().use{...}.
- ¡PELIGRO! Requiere cerrar el recurso manualmente (
- Ventajas:
Ejemplo 3
Queremos crear un informe de toda la estructura de la carpeta resultante del ejemplo anterior. Por tanto necesitamos entrar en las nuevas carpetas (pdf, jpg, txt) y ver qué ficheros hay dentro de cada una. Para ello se utiliza Files.walk() que calcula la profundidad, recorre la jerarquía de carpetas y muestra cada elemento indicando si es un directorio o un fichero.
🔍 Ejecutar y Analizar
Ejecuta el ejemplo anterior y comprueba que la salida es la siguiente:
🎯 Práctica 2: Directorios y comprobaciones
🎯 Práctica 2: Directorios y comprobaciones
Prepara la estructura de tu proyecto. Crea la ruta proyecto/datos. Basándote en los ejemplos anteriores, desarrolla un programa en tu proyecto haga lo siguiente:
- Defina dos rutas: una para una carpeta llamada
datos_iniy otra para una carpeta llamadadatos_fin(ambas dentro de la carpetaproyecto/datosde tu proyecto). - Comprueba los directorios: Si las carpetas no existen las deberá crear utilizando
Files.createDirectories. - Añade ficheros: Añade (manualmente y vacío) el fichero
mis_datos.jsondentro de la carpetadatos_ini. - Comprueba ficheros: Después de la comprobación de la existencia del fichero de datos dentro de la carpeta
datos_ini(mis_datos.json) imprimirá un mensaje por consola mostrando la estrctura de directorios y ficheros.
La salida de tu programa debe ser parecida a esta, la primera vez que se ejecuta:
Y la segunda vez que se ejecuta, tras añadir el fichero mis_datos.json:
La estructura en tu proyecto debe ser parecida a esta:
