De todas las herramientas con las que cuenta el desarrollador de NodeJS, una de las más potentes es sin duda los streams. Entre ellos, los streams de lectura (Readable stream o ReadStream) son los que usarás con más frecuencia. Ya sea para leer un fichero o para descargarte algo de internet, tienes que usar una implementación de un ReadStream.

¿Pero qué es un ReadStream? Si traducimos literalmente de la documentación de NodeJS, La interfaz Readable stream es la abstracción de una fuente de datos desde la que estás leyendo. En otras palabras, los datos provienen de un Readble stream.

La verdad es que esa descripción no me parece demasiado iluminadora. Así que voy a tratar de hacerle caso a Steven Pinker en su libro The Sense Of Style, y voy a tratar de crear una imagen en tu cabeza que haga más fácil entender el concepto.

Imagínate que tienes una piscina y que quieres vaciarla. Decides llamar a un fontanero para que te instale una bomba de agua conectada con tu piscina.

var bombaAgua = require( 'fontanero' ).instalarBombaAgua( 'piscina' );  

¡Genial! Ya tenemos la instalación terminada. Esta bomba es un tanto especial, tiene dos modalidades de funcionamiento.

La más básica, donde tendremos un caudal constante de agua y nosotros somos los responsable de abrir o cerrar la bomba.

bomba.on( 'caudal-saliendo', function(agua){  
    var deposito += agua;
    if(deposito.estaLleno()){
        bomba.parar()
        deposito.vaciar(function(){
            bomba.reanudar();
        });
    }
} );

Como ves, es nuestra responsabilidad detener el flujo de agua cuando ya no quepa más agua en el depósito al cual has enviado el agua; habrá que vaciarlo y volver a abrir el flujo de agua cuando el deposito esté vacío.

La otra modalidad de funcionamiento de la bomba es algo más sofisticada. Aquí solo nos avisa cuando está listo para empezar a bombear agua y nosotros somos los encargados de empezar a bombear e incluso de decidir cuál es el caudal más adecuado.

bomba.on( 'listo-para-bombear', function(){  
    while( !deposito.estaLleno()){
        deposito += bomba.bombear();
    }
} )

En cualquier caso, cuando nuestra piscina esté vacía siempre vamos a recibir una notificación de que ya no hay más agua.

bomba.on( 'vacia' );  

Ahora que tienes una imagen de algo simple en tu cabeza vamos a traducir todos esos conceptos a código NodeJS para que veas cómo realmente funcionan. Para ello vamos a usar el típico ejemplo de la lectura de un fichero de disco.

Usaremos el módulo FileSystem para crear un ReadStream sobre un un fichero.

var myStream = require( 'fs' ).createReadStream( 'hola.txt' );  

El stream comienza SIEMPRE en estado paused; seremos nosotros, al añadirle un handler para el evento data, los que hagamos que pase a unpaused y empiece a emitir datos.

myStream.on( 'data', function( data ){  
  console.log( data.toString() );
} );

Todo lo que emiten los streams son objetos de tipo Buffer, así que si deseas ver su representación en texto tendrás que convertirlos a texto o configurar el stream como utf8 del siguiente modo: myStrean.setEncodig( 'utf8' );

Tras ejecutar eso deberías ver con consola el contenido íntegro del fichero hola.txt.

Otra forma de leer el contenido del fichero es, como hemos comentado, siendo nosotros los que le pedimos al stream que nos proporcione datos nuevos.

myStream.on( 'readable', function(){  
  var chunk;
  while( chunk = myStream.read() ){
    console.log( chunk.toString() );
  }
} );

Recuerda que siempre que llames a la función read() sobre un stream que esté paused automáticamente pasa a estar unpaused.

Hasta aquí la parte más básica de los ReadStream. En próximos post vendrán los WriteStream y veremos cómo usar pipes para "enchufar" directamente la salida de una ReadStream a la entrada de un WriteStream.

También queda pendiente cómo crear tu propio ReadStream y no solo cómo usar los de otros.

Si quieres seguir aprendiendo sobre NodeJS, suscríbete y mantente al día.

Suscríbete a mi lista de correo

* Campos obligatorios