Atlasingeniería

Algoritmos y programaciónManejo de datosTema 4

Archivos y entrada y salida

La entrada y salida conecta el programa con recursos que fallan, llegan por partes y tienen formatos. Separar bytes, parsing y lógica vuelve esos límites controlables.

Para este tema conviene tener claro:Cadenas de texto

Dentro del programa, una suma suele terminar o lanzar un error predecible. Afuera hay archivos que faltan, permisos, discos llenos y datos cortados. Entrada y salida es una frontera con un mundo que no controlamos.

Bytes, texto, datos y dominio

Un archivo contiene bytes. La codificación transforma bytes en texto; el parser transforma texto en datos; la validación decide si esos datos pertenecen al dominio. Mezclar las tres capas produce errores difíciles de ubicar.

Una ruta válida no garantiza que el contenido exista ni tenga el formato esperado. Cada etapa necesita un resultado o error que preserve contexto suficiente para diagnosticarla.

Antes de seguir, predecí

Leés un CSV de 2 GB con una sola llamada que devuelve todo el contenido. ¿Qué pasa?

Abrir es pedir un recurso prestado

Abrir un archivo adquiere un recurso del sistema operativo. Debe cerrarse incluso si el procesamiento falla. Los lenguajes ofrecen bloques o APIs que garantizan limpieza al salir de un alcance.

Leer todo de una vez es simple, pero usa memoria proporcional al archivo. Para entradas grandes, un stream procesa fragmentos y mantiene acotada la memoria, a cambio de manejar límites parciales.

Escribir sin dejar el archivo a medias

Una escritura puede interrumpirse y dejar contenido incompleto. Para reemplazar configuración o datos importantes, una estrategia común escribe un archivo temporal, fuerza las comprobaciones y lo renombra dentro del mismo sistema de archivos.

Eso reduce la ventana de corrupción, pero durabilidad y atomicidad exactas dependen del sistema. No hay que presentar “guardar” como una única operación infalible.

CSV y JSON: las reglas que muerden

CSV, JSON y formatos binarios tienen reglas propias. Separadores escapados, saltos de línea, zonas horarias y versiones de schema convierten un ejemplo pequeño en un contrato real.

Validar después de parsear evita que datos estructuralmente válidos pero semánticamente imposibles entren al núcleo. Los mensajes de error deberían indicar archivo y ubicación sin exponer contenido sensible innecesario.

Las tres capas, una por una

Un archivo de precios que llega todos los días. La ruta existe, y eso es lo único que sabemos.

1 / 6
Cada fila es una capa y cada una falla distinto. Mezclarlas es lo que produce un error de validación que en realidad era de codificación, y una hora buscando en el lugar equivocado. La pregunta útil no es «¿por qué falla?» sino «¿en qué capa falla?».

Leer entero contra leer de a pedazos

import { readFile } from 'node:fs/promises';
import { createReadStream } from 'node:fs';
import { createInterface } from 'node:readline';

// 1. Todo en memoria: simple, y sólo sirve si el archivo es chico
const parseWhole = async (path: string): Promise<string[]> => {
  const content = await readFile(path, 'utf8'); // un archivo de 2 GB son 2 GB de memoria
  return content.split('\n');
};

// 2. De a una línea: memoria constante, sirva el archivo que sirva
const countLines = async (path: string): Promise<number> => {
  const stream = createReadStream(path, { encoding: 'utf8' });
  const lines = createInterface({ input: stream, crlfDelay: Infinity });

  let total = 0;
  for await (const line of lines) {
    if (line.trim() !== '') total += 1;
  }
  return total;
};

La diferencia entre las dos no es de estilo: la primera funciona en desarrollo con el archivo de prueba de diez líneas y tira el proceso en producción con el archivo real. Y el encoding no es opcional: sin él, lo que llega son bytes, y partir bytes por el medio de un carácter de varios bytes produce texto roto.

La frontera con el mundo

Lo que puede fallarCuándo se notaQué corresponde hacer
El archivo no existeal abrirerror claro con la ruta adentro
No hay permisosal abrirlo mismo: es un problema de entorno, no de datos
La codificación no es la esperadanunca: salen caracteres rarosdeclararla y validar
El contenido no tiene el formatoal parseardecir qué línea y qué se esperaba
El disco se llena al escribira mitad de caminoescribir a un temporal y renombrar al final
El proceso muere escribiendodespués: queda medio archivolo mismo: renombrar es atómico
Las dos últimas filas son la misma técnica y resuelven el problema más difícil de la escritura: que un archivo a medio escribir nunca se vea como uno completo.

Cierre

Entrada y salida exige pensar en recursos, fragmentos y fallas parciales. Separá lectura de bytes, decodificación, parsing y validación. Así la lógica principal trabaja con datos confiables y la frontera conserva los detalles del error.

Autoevaluación

¿Lo entendiste?

¿Cuáles son las tres capas que conviene no mezclar al leer un archivo?
Leer todo el archivo de una vez, ¿cuándo deja de servir?
¿Por qué para reemplazar un archivo importante se escribe uno temporal y después se renombra?
El JSON parseó bien. ¿Ya se puede usar?