Archivos
¿Por qué archivos?
Hasta ahora, todos nuestros programas pierden sus datos cuando terminan de ejecutarse. Las variables solo existen mientras el programa está vivo. Pero ¿qué pasa si quieres guardar un puntaje alto, almacenar una configuración, o procesar un log? Para eso están los archivos.
Los archivos permiten que tus programas persistan datos — guardarlos en disco para que sobrevivan después de que el programa termine, y leerlos de vuelta después.
Leer un archivo
La operación más simple es leer un archivo completo en un string:
import { read_file } from "std/file" fn main() { let contenido: String = read_file("mensaje.txt") print(contenido) }
Si mensaje.txt contiene ¡Hola desde un archivo!, el programa imprime exactamente eso.
read_file devuelve el archivo completo como un solo string, incluyendo saltos de línea. Es la forma más fácil de obtener datos de un archivo.
Escribir un archivo
Para guardar datos, usa write_file:
import { write_file } from "std/file" fn main() { write_file("salida.txt", "¡Nyx estuvo aquí!") print("Archivo escrito exitosamente") }
Esto crea salida.txt (o lo sobrescribe si ya existe) con el texto ¡Nyx estuvo aquí!.
write_file devuelve 1 en caso de éxito.
Verificar si un archivo existe
Antes de leer un archivo, podrías querer verificar si realmente existe:
import { read_file, file_exists } from "std/file" fn main() { if file_exists("config.txt") { let config: String = read_file("config.txt") print("Config cargada: " + config) } else { print("No se encontró archivo de config, usando valores por defecto") } }
file_exists devuelve true si el archivo está en disco, false en caso contrario.
Trabajar con líneas
Los archivos a menudo contienen múltiples líneas de datos. Puedes usar .split() para dividir el contenido en líneas:
import { read_file } from "std/file" fn main() { let contenido: String = read_file("nombres.txt") let lineas: Array = contenido.split("\n") var i: int = 0 while i < lineas.length() { print("Línea " + int_to_string(i + 1) + ": " + lineas[i]) i += 1 } }
Si nombres.txt contiene:
Alice Bob Charlie
Salida:
Línea 1: Alice Línea 2: Bob Línea 3: Charlie
Escribir múltiples líneas
Para escribir múltiples líneas, únelas con caracteres de salto de línea:
import { write_file } from "std/file" fn main() { let nombres: Array = ["Alice", "Bob", "Charlie", "Diana"] var contenido: String = "" var i: int = 0 while i < nombres.length() { contenido = contenido + nombres[i] + "\n" i += 1 } write_file("nombres.txt", contenido) print("Se escribieron " + int_to_string(nombres.length()) + " nombres") }
Ejemplo práctico: un archivo de configuración simple
Muchos programas usan archivos de configuración para almacenar ajustes. Construyamos un lector simple de config clave=valor:
import { read_file, write_file, file_exists } from "std/file" fn cargar_config(ruta: String) -> Map { var config: Map = Map.new() if file_exists(ruta) { let contenido: String = read_file(ruta) let lineas: Array = contenido.split("\n") var i: int = 0 while i < lineas.length() { let linea: String = lineas[i] let pos_eq: int = linea.indexOf("=") if pos_eq > 0 { let clave: String = linea.substring(0, pos_eq) let valor: String = linea.substring(pos_eq + 1, linea.length()) config.insert(clave, valor) } i += 1 } } return config } fn guardar_config(ruta: String, config: Map) { var contenido: String = "" if config.contains("host") { contenido = contenido + "host=" + config.get("host") + "\n" } if config.contains("port") { contenido = contenido + "port=" + config.get("port") + "\n" } if config.contains("debug") { contenido = contenido + "debug=" + config.get("debug") + "\n" } write_file(ruta, contenido) } fn main() { let config: Map = cargar_config("app.conf") if config.contains("host") { print("Host: " + config.get("host")) } else { print("No se encontró config, creando valores por defecto...") var defaults: Map = Map.new() defaults.insert("host", "localhost") defaults.insert("port", "8080") defaults.insert("debug", "false") guardar_config("app.conf", defaults) print("Config por defecto guardada en app.conf") } }
Ejemplo práctico: un logger simple
import { read_file, write_file, file_exists } from "std/file" fn registrar_mensaje(ruta: String, mensaje: String) { var contenido: String = "" if file_exists(ruta) { contenido = read_file(ruta) } contenido = contenido + mensaje + "\n" write_file(ruta, contenido) } fn main() { let archivo_log: String = "app.log" registrar_mensaje(archivo_log, "Aplicación iniciada") registrar_mensaje(archivo_log, "Procesando datos...") registrar_mensaje(archivo_log, "¡Listo!") print("Contenido del log:") print(read_file(archivo_log)) }
Salida:
Contenido del log: Aplicación iniciada Procesando datos... ¡Listo!
Ejemplo práctico: procesamiento de datos CSV
CSV (Valores Separados por Comas) es un formato de archivo común. Leamos y procesemos uno:
import { read_file } from "std/file" struct Producto { nombre: String, precio: int, cantidad: int } fn parsear_csv(contenido: String) -> Array { let lineas: Array = contenido.split("\n") var productos: Array = [] // Saltar línea de encabezado, empezar en 1 var i: int = 1 while i < lineas.length() { let linea: String = lineas[i] if linea.length() > 0 { let campos: Array = linea.split(",") let p: Producto = Producto { nombre: campos[0], precio: string_to_int(campos[1]), cantidad: string_to_int(campos[2]) } productos.push(p) } i += 1 } return productos } fn main() { // Asumimos que inventario.csv contiene: // nombre,precio,cantidad // Manzana,2,50 // Pan,3,20 // Leche,4,30 let contenido: String = read_file("inventario.csv") let productos: Array = parsear_csv(contenido) var valor_total: int = 0 var i: int = 0 while i < productos.length() { let p: Producto = productos[i] let valor: int = p.precio * p.cantidad print(p.nombre + ": $" + int_to_string(valor)) valor_total += valor i += 1 } print("Valor total del inventario: $" + int_to_string(valor_total)) }
Ejercicios
- Escribe un programa que lea un archivo de números (uno por línea) e imprima la suma, promedio, mínimo y máximo.
- Escribe un programa de "lista de tareas" que guarde tareas en
tareas.txt. Debe poder agregar una tarea (añadir una línea) y mostrar todas las tareas (leer e imprimir).
- Escribe un programa que lea un archivo de texto y cuente cuántas veces aparece cada palabra. Imprime los conteos.
- Escribe un programa que copie un archivo a otro: lee el origen, escribe en el destino, e imprime un mensaje de confirmación.
- Escribe un programa que lea un CSV con nombres de estudiantes y notas, calcule el promedio de cada estudiante, y escriba un informe resumen en un archivo nuevo.
Resumen
read_file(ruta)lee un archivo completo en un string.write_file(ruta, contenido)escribe un string a un archivo (crea o sobrescribe).file_exists(ruta)verifica si un archivo existe en disco.- Usa
.split("\n")para dividir el contenido en líneas. - Usa concatenación de strings con
"\n"para construir contenido multilínea. - Los archivos permiten que tus programas guarden y carguen datos que persisten entre ejecuciones.
Siguiente capítulo: Closures y funciones de primera clase →