Node.js Stream (flujo)
Stream de Node.js es una interfaz abstracta para manejar datos en flujo, ampliamente utilizada en operaciones de archivos, comunicaciones de red, etc.
Una de las principales ventajas del procesamiento de datos en flujo es que se pueden empezar a procesar los datos durante la transmisión sin tener que esperar a que se carguen todos los datos, lo que permite a Node.js manejar grandes cantidades de datos de manera eficiente sin consumir demasiada memoria.

Stream es una interfaz abstracta; en Node muchos objetos implementan esta interfaz. Por ejemplo, el objeto request de una petición a un servidor http es un Stream, al igual que stdout (salida estándar).
Stream (flujo) de Node.js es una forma de manejar flujos de datos que te permite procesar datos en forma de flujo en lugar de cargarlos todos en la memoria de una vez. Esto es muy útil para manejar grandes volúmenes de datos o lograr una transferencia de datos eficiente.
En Node.js, Stream tiene cuatro tipos de flujo:
Readable- Operación de lectura.
Writable- Operación de escritura.
Duplex- Operación de lectura y escritura.
Transform- La operación escribe datos y luego lee el resultado.
Todos los objetos Stream son instancias de EventEmitter. Los eventos comunes son:
data- Se dispara cuando hay datos para leer.
end- Se dispara cuando no hay más datos para leer.
error- Se dispara cuando ocurre un error durante la recepción y escritura.
finish- Se dispara cuando todos los datos han sido escritos en el sistema subyacente.
Este tutorial presentará las operaciones de flujo más comunes.
Leer datos de un flujo
Los flujos legibles comunes incluyen flujos de lectura de archivos y flujos de respuesta a solicitudes de red.
Crea un archivo input.txt con el siguiente contenido:
Ejemplo官网地址:www.example.com
Crea un archivo main.js, con el siguiente código:
Ejemplo
var data = '';
// Crear un flujo legible
var readerStream = fs.createReadStream('input.txt');
// Establecer la codificación a utf8.
readerStream.setEncoding('UTF8');
// Manejar eventos de flujo --> data, end y error
readerStream.on('data', function(chunk) {
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("El programa ha terminado de ejecutarse");
El resultado de ejecutar el código anterior es el siguiente:
程序执行完毕 Ejemplo官网地址:www.example.com
Flujo de escritura
Los flujos de escritura se utilizan para escribir datos en un destino; los flujos de escritura comunes incluyen flujos de escritura de archivos y flujos de envío de solicitudes de red.
Crea un archivo main.js, con el siguiente código:
Ejemplo
var data = 'Dirección web oficial del tutorial de novatos: www.example.com';
// Crear un flujo de escritura, escribir en el archivo output.txt
var writerStream = fs.createWriteStream('output.txt');
// Escribir datos usando codificación utf8
writerStream.write(data,'UTF8');
// Marcar el final del archivo
writerStream.end();
// Manejar eventos de flujo --> finish, error
writerStream.on('finish', function() {
console.log("Escritura completada.");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("El programa ha terminado de ejecutarse");
El programa anterior escribirá los datos de la variable data en el archivo output.txt. El resultado de ejecutar el código es el siguiente:
$ node main.js 程序执行完毕 写入完成。
Ver el contenido del archivo output.txt:
$ cat output.txt Ejemplo官网地址:www.example.com
Flujo dúplex (Duplex)
Un flujo dúplex tiene capacidades de lectura y escritura al mismo tiempo.
Un ejemplo típico de flujo dúplex es un socket TCP.
Ejemplo
// Crear un servidor TCP
const server = net.createServer((socket) => {
console.log('Client connected.');
// Leer datos del cliente
socket.on('data', (data) => {
console.log('Received data:', data.toString());
});
// Enviar datos al cliente
socket.write('Hello, Client!\n');
// Escuchar el evento de cierre
socket.on('end', () => {
console.log('Client disconnected.');
});
});
server.listen(3000, () => {
console.log('Server listening on port 3000.');
});
Flujo de transformación (Transform)
Un flujo de transformación es un tipo especial de flujo dúplex que puede modificar o transformar datos. Los flujos de transformación comunes incluyen flujos de compresión y descompresión.
Ejemplo
const fs = require('fs');
// Crear un flujo legible
const readableStream = fs.createReadStream('example.txt');
// Crear un flujo de transformación (compresión)
const gzip = zlib.createGzip();
// Crear un flujo de escritura
const writableStream = fs.createWriteStream('example.txt.gz');
// Pasar el flujo legible al flujo de transformación mediante pipe, y luego al flujo de escritura
readableStream.pipe(gzip).pipe(writableStream);
// Escuchar el evento de finalización
writableStream.on('finish', () => {
console.log('File compressed successfully.');
});
Flujo de tubería
El pipe proporciona un mecanismo de flujo de salida a flujo de entrada.
Normalmente se utiliza para obtener datos de un flujo y pasarlos a otro flujo.
Como se muestra en la imagen anterior, comparamos los archivos con cubos de agua, donde el agua es el contenido del archivo. Usamos una tubería (pipe) para conectar dos cubos, haciendo que el agua fluya de un cubo a otro, logrando así gradualmente el proceso de copia de archivos grandes.
En el siguiente ejemplo, leemos el contenido de un archivo y lo escribimos en otro archivo.
Establece el contenido del archivo input.txt de la siguiente manera:
Ejemplo官网地址:www.example.com 管道流操作实例
Crea un archivo main.js, con el siguiente código:
Ejemplo
// Crear un flujo legible
var readerStream = fs.createReadStream('input.txt');
// Crear un flujo de escritura
var writerStream = fs.createWriteStream('output.txt');
// Operación de lectura y escritura mediante pipe
// Leer el contenido del archivo input.txt y escribirlo en el archivo output.txt
readerStream.pipe(writerStream);
console.log("El programa ha terminado de ejecutarse");
El resultado de ejecutar el código es el siguiente:
$ node main.js 程序执行完毕
Ver el contenido del archivo output.txt:
$ cat output.txt Ejemplo官网地址:www.example.com 管道流操作实例
Flujo en cadena
La cadena es un mecanismo que conecta un flujo de salida a otro flujo y crea una cadena de operaciones de flujo múltiples.
El flujo en cadena se usa generalmente para operaciones de pipe.
A continuación, usaremos pipe y cadenas para comprimir y descomprimir archivos.
Crea un archivo compress.js, con el siguiente código:
Ejemplo
var zlib = require('zlib');
// Comprimir el archivo input.txt a input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
console.log("Compresión de archivo completada.");
El resultado de ejecutar el código es el siguiente:
$ node compress.js 文件压缩完成。
Después de ejecutar las operaciones anteriores, podemos ver que se ha generado el archivo comprimido input.txt.gz de input.txt en el directorio actual.
A continuación, descomprimamos ese archivo. Crea un archivo decompress.js, con el siguiente código:
Ejemplo
var zlib = require('zlib');
// Descomprimir el archivo input.txt.gz a input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("Descompresión de archivo completada.");
El resultado de ejecutar el código es el siguiente:
$ node decompress.js 文件解压完成。
Pausar y reanudar
Un flujo legible puede pausar y reanudar la lectura de datos.
Ejemplo
const readableStream = fs.createReadStream('example.txt', 'utf8');
readableStream.on('data', (chunk) => {
console.log('Received chunk:', chunk);
readableStream.pause(); // Pausar lectura
setTimeout(() => {
readableStream.resume(); // Reanudar lectura
}, 1000);
});
Destruir
Se puede destruir el flujo para liberar recursos.
Ejemplo
const readableStream = fs.createReadStream('example.txt', 'utf8');
readableStream.on('data', (chunk) => {
console.log('Received chunk:', chunk);
readableStream.destroy(); // Destruir flujo
});