Los streams son flujos de datos que se leen o escriben de forma continua, lo que permite manejar más rápido y eficiente de grandes cantidades de datos.
Los streams nos permiten trabajar con grandes cantidades de datos sin tener que cargar todo el contenido en memoria (esto es especialmente útil cuando trabajamos con archivos o comunicaciones de red de gran tamaño)
En Node.js, los streams se dividen en diferentes tipos:
- Readable Streams: Permiten leer datos de una fuente, como un archivo o una solicitud HTTP
- Writable Streams: Permiten escribir datos en un destino, como un archivo o una respuesta HTTP
- Duplex Streams: Permiten leer y escribir datos, como en una conexión de red TCP
Ejemplos de uso de Streams
Leer un Archivo con Readable Streams
Para leer un archivo utilizando un Readable Stream en Node.js, podemos hacer lo siguiente:
import fs from 'node:fs';
const readableStream = fs.createReadStream('archivo.txt', 'utf8');
readableStream.on('data', (chunk) => {
console.log('Datos recibidos:', chunk);
});
readableStream.on('end', () => {
console.log('Lectura de archivo completa');
});
readableStream.on('error', (err) => {
console.error('Error al leer el archivo:', err);
});
::::
En este ejemplo, Creamos un Readable Stream utilizando el método createReadStream()
del módulo fs
. Este método toma dos argumentos: el nombre del archivo del que queremos leer (archivo.txt
en este caso) y la codificación de caracteres (utf8
en este caso).
Por otro lado, asociamos gestionamos tres eventos:
data
: Este evento se dispara cada vez que se recibe un fragmento de datos del archivo.end
: Este evento se emite cuando se completa la lectura del archivo.error
: Este evento se dispara si se produce algún error durante la lectura del archivo.
Escribir en un Archivo con Writable Streams
Para escribir en un archivo utilizando un Writable Stream en Node.js, podemos hacer lo siguiente:
import fs from 'node:fs';
const writableStream = fs.createWriteStream('nuevoArchivo.txt', 'utf8');
writableStream.write('Esto es un texto que será escrito en el archivo.\n');
writableStream.write('Podemos escribir datos de forma incremental.\n');
writableStream.end('Finalizando escritura en el archivo.\n');
writableStream.on('finish', () => {
console.log('Escritura de archivo completa');
});
writableStream.on('error', (err) => {
console.error('Error al escribir en el archivo:', err);
});
En este ejemplo, creamos un Writable Stream utilizando el método createWriteStream()
del módulo fs
. Este método toma dos argumentos: el nombre del archivo en el que queremos escribir (nuevoArchivo.txt
en este caso) y la codificación de caracteres (utf8
en este caso).
Usamos el método write()
para escribir datos en el archivo. Finalmente llamamos al método end()
para indicar que hemos terminado de escribir en el archivo.
Por otro lado, asociamos gestionamos dos eventos:
finish
: Este evento se emite cuando la escritura en el archivo se ha completado correctamente.error
: Este evento se emite si se produce algún error durante la escritura en el archivo.
Piping (tubería) entre streams
El piping entre streams es una técnica común en Node.js que permite redirigir la salida de un stream a la entrada de otro. Por ejemplo, podemos copiar un archivo utilizando piping de la siguiente manera:
import { createReadStream, createWriteStream } from 'node:fs';
const readStream = createReadStream('archivo.txt');
const writeStream = createWriteStream('copiaArchivo.txt');
readStream.pipe(writeStream);
writeStream.on('finish', () => {
console.log('Archivo copiado exitosamente.');
});
writeStream.on('error', (err) => {
console.error('Error al copiar el archivo:', err);
});
En este ejemplo, creamos un Readable Stream utilizando createReadStream()
y un Writable Stream utilizando createWriteStream()
. Luego, utilizamos el método pipe()
para redirigir los datos del stream de lectura al stream de escritura.
Combinar múltiples streams
También podemos combinar múltiples streams para realizar operaciones más complejas. Por ejemplo, podemos transformar un archivo a mayúsculas mientras lo copiamos utilizando streams de transformación:
import { createReadStream, createWriteStream } from 'node:fs';
const { Transform } = require('node:stream');
const readStream = createReadStream('archivo.txt', 'utf8');
const writeStream = createWriteStream('mayusculas.txt');
const transformStream = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});
readStream.pipe(transformStream).pipe(writeStream);
writeStream.on('finish', () => {
console.log('Archivo transformado y escrito en mayúsculas.');
});
writeStream.on('error', (err) => {
console.error('Error al transformar y escribir el archivo:', err);
});
En este ejemplo, creamos un stream de transformación utilizando la clase Transform y definimos la lógica de transformación en el método transform(). Luego, utilizamos el método pipe() para encadenar los streams de lectura, transformación y escritura.
Descarga el código
Todo el código de esta entrada está disponible para su descarga en Github