7.B Archivos y carpetas¶
Los programas guardan datos en archivos, organizados en carpetas (directorios). Saber consultar, crear, copiar, mover y borrar es la base para cualquier programa que trabaje con datos que deben sobrevivir al cierre.
Qué excepción salta y qué no
Aquí se usan las operaciones de File y Directory. En 7.E están las excepciones concretas de cada una (PathExistsException, PathNotFoundException...) y las operaciones que no dan error aunque el destino exista, como copySync o renameSync.
Rutas¶
Una ruta indica dónde está un archivo o carpeta.
| Tipo | Ejemplo | Significa |
|---|---|---|
| Absoluta | C:/Users/ana/datos/notas.txt (Windows) · /home/ana/datos/notas.txt (Linux, macOS) |
Desde la raíz del sistema |
| Relativa | datos/notas.txt |
Desde la carpeta de trabajo del programa (la carpeta desde la que se ejecuta) |
Usa / en las rutas
Aunque Windows escribe las rutas con \, en Dart (y en los otros tres lenguajes) la barra normal / funciona en todos los sistemas y evita problemas con el carácter de escape \.
Las operaciones básicas¶
Se usan las clases de dart:io: File (un archivo), Directory (una carpeta) y FileSystemEntity, que es la base de ambas y permite preguntar el tipo de una ruta (FileSystemEntity.isDirectorySync(ruta)). Casi todo tiene dos versiones: la síncrona (...Sync, que se usa aquí por sencillez) y la asíncrona (con Future), que no bloquea el programa. Para trabajar con rutas (unir, sacar el nombre, la extensión) existe el paquete path de pub.dev, que no es parte del SDK.
import 'dart:io';
String nombre(FileSystemEntity e) => e.uri.pathSegments.lastWhere((s) => s.isNotEmpty);
List<String> nombres(Directory carpeta) => carpeta.listSync().map(nombre).toList()..sort();
void main() {
final carpeta = Directory('datos');
Directory('datos/sub').createSync(recursive: true);
print('carpeta creada: ${carpeta.existsSync() ? 'sí' : 'no'}');
File('datos/notas.txt').writeAsStringSync('uno\ndos\n');
for (final n in nombres(carpeta)) {
final ruta = '${carpeta.path}/$n';
if (FileSystemEntity.isDirectorySync(ruta)) {
print('$n: carpeta');
} else {
print('$n: archivo de ${File(ruta).lengthSync()} bytes');
}
}
File('datos/notas.txt').copySync('datos/notas_copia.txt');
print('tras copiar: ${nombres(carpeta).join(', ')}');
File('datos/notas_copia.txt').renameSync('datos/resumen.txt');
print('tras renombrar: ${nombres(carpeta).join(', ')}');
carpeta.deleteSync(recursive: true);
print('datos existe tras borrar: ${carpeta.existsSync() ? 'sí' : 'no'}');
}
Salida:
carpeta creada: sí
notas.txt: archivo de 8 bytes
sub: carpeta
tras copiar: notas.txt, notas_copia.txt, sub
tras renombrar: notas.txt, resumen.txt, sub
datos existe tras borrar: no
El programa crea una carpeta con una subcarpeta, escribe un archivo, inspecciona lo que hay (¿archivo o carpeta? ¿cuánto ocupa?), lo copia, lo renombra y lo borra todo al final. Fíjate en que la lista de nombres se ordena antes de mostrarla: el sistema no garantiza ningún orden al listar una carpeta.
| Necesito... | En Dart |
|---|---|
| ¿Existe? ¿Es carpeta? | File(r).existsSync() · FileSystemEntity.isDirectorySync(r) |
| Tamaño en bytes | File(r).lengthSync() |
| Crear carpeta (con las que falten) | Directory(r).createSync(recursive: true) |
| Listar el contenido | Directory(r).listSync() |
| Copiar · renombrar o mover | File(r).copySync(destino) · File(r).renameSync(destino) |
| Borrar archivo · carpeta con todo lo que contiene | File(r).deleteSync() · Directory(r).deleteSync(recursive: true) |
Cuando algo falla¶
Un archivo que no existe o sin permisos lanza una FileSystemException (o una subclase, como PathNotFoundException).
Los fallos son normales con archivos (el usuario escribe mal una ruta, el disco está lleno, otro programa tiene el archivo abierto). Un programa robusto comprueba antes lo que pueda (¿existe?) y captura lo demás para dar un mensaje claro.
Cuidado con lo que borras
Borrar con recursive, rmtree, deleteRecursively o walk elimina todo lo que haya dentro, sin papelera y sin vuelta atrás. Antes de borrar:
- Comprueba que la ruta es la que esperas (no vacía, no la raíz de un disco, no tu carpeta de usuario).
- Si el borrado lo decide el usuario, pídele confirmación.
- Mientras pruebas, usa una carpeta de prueba aparte.
Errores frecuentes¶
| Error | Cómo evitarlo |
|---|---|
| Rutas relativas que dependen de dónde se ejecute el programa | Comprobar la carpeta de trabajo, o usar rutas absolutas |
| Asumir un orden al listar una carpeta | Ordenar los nombres |
| Sobrescribir un archivo existente sin avisar | Comprobar si existe y preguntar antes |
| Borrar una carpeta no vacía con la función de un solo archivo | Usar la versión recursiva, con confirmación |
Olvidar cerrar lo que se abre (en Java, Files.list) |
try-with-resources |
Para practicar¶
Haz los ejercicios de U7.2 · Archivos y carpetas. Y para ver cómo se escribe en otro lenguaje: Pasar de uno a otro.