Streams
Un stream procesa datos en pedazos (chunks) a medida que llegan, en vez de esperar a tener todo el contenido en memoria antes de empezar. Para un archivo de 2GB, la diferencia es literal entre “usa 2GB de RAM” y “usa unos pocos KB, sin importar el tamaño del archivo”.
Los tipos básicos
Sección titulada «Los tipos básicos»Readable → de donde se leen datos (un archivo, una request HTTP entrante)Writable → a donde se escriben datos (un archivo, una response HTTP)Duplex → los dos a la vez (un socket TCP)Transform → Duplex que además modifica los datos que pasan (compresión, encriptado)Leer un archivo grande como stream
Sección titulada «Leer un archivo grande como stream»import { createReadStream } from "node:fs"
const stream = createReadStream("archivo-grande.csv", { encoding: "utf-8" })
stream.on("data", (chunk) => { console.log("Pedazo recibido:", chunk.length, "bytes")})
stream.on("end", () => { console.log("Terminó de leer todo")})
stream.on("error", (err) => { console.error("Algo falló:", err)})Comparar con readFile (de Filesystem): ese carga el archivo completo en memoria antes de devolver algo — para un archivo de unos KB no importa, para uno de varios GB puede tirar el proceso por falta de memoria.
.pipe(): conectar un Readable a un Writable
Sección titulada «.pipe(): conectar un Readable a un Writable»import { createReadStream, createWriteStream } from "node:fs"
createReadStream("origen.txt").pipe(createWriteStream("copia.txt")).pipe() maneja automáticamente el backpressure: si el destino (Writable) es más lento consumiendo que el origen (Readable) produciendo, pausa la lectura hasta que el destino esté listo para más — sin esto, un stream rápido escribiendo a uno lento acumularía todo en memoria de todas formas, perdiendo la ventaja de usar streams en primer lugar.
Streams en un servidor HTTP
Sección titulada «Streams en un servidor HTTP»req y res en un servidor Node son streams (req es Readable y res es Writable). Por eso, en el servidor HTTP nativo, leer el body de una request implica escuchar data y end en vez de recibirlo ya construido.
import { createReadStream } from "node:fs"import { createServer } from "node:http"
const server = createServer((req, res) => { if (req.url === "/descargar") { // el archivo se transmite en pedazos directo a la respuesta, // sin cargarlo entero en memoria del servidor createReadStream("archivo-grande.zip").pipe(res) }})Referencia de streams
Sección titulada «Referencia de streams»| Concepto | Qué es |
|---|---|
Readable | Fuente de datos, en pedazos (data/end/error) |
Writable | Destino de datos |
.pipe(destino) | Conecta ambos, maneja backpressure automáticamente |
| Backpressure | El mecanismo que evita que un productor rápido sature a un consumidor lento |
Cuándo usar streams
Sección titulada «Cuándo usar streams»- Para la mayoría del código de aplicación (leer un archivo de config chico, un JSON pequeño),
readFile/writeFilenormal es más simple y perfectamente adecuado — streams importan específicamente cuando el tamaño de los datos es grande o desconocido de antemano (archivos, uploads, respuestas HTTP grandes). req.on('data', ...)consume manualmente un streamReadable; frameworks como Express encapsulan ese trabajo con middleware de parsing.