Reading Data In Chunks With Readable Streams
A Readable Stream Of Data From A Local File
In this example, a text file, called longfile.txt
, gets read in chunks. The size of the file will impact the number of chunks that gets read.
This uses a native readable stream, createReadStream, to read data from a file one chunk at a time.
//
// dependencies
//
const { createReadStream } = require('fs');
//
// variables
//
const THE_FILE_TO_READ = './longfile.txt';
const EVENTS = {
DATA: 'data',
END: 'end',
}
let howManyChunks = 1;
//
// functional logic
//
const readStream = createReadStream(THE_FILE_TO_READ);
function readChunk(data) {
console.log(`got chunk # ${${howManyChunks}}`, data);
howManyChunks++;
console.log('\n');
}
function endReading() {
console.log(' finished reading');
}
readStream.on(EVENTS.DATA, readChunk);
readStream.on(EVENTS.END, endReading);
Creating a Readable Stream Object From Scratch
Node comes with a readable stream factory function that can be used to create a "lower level" readable stream. The above example is connected to the fs
module, but this Readable
function is more interpretable to a developers' needs:
const { Readable } = require('stream');
const madeUpData = ['some', 'data', 'to', 'read'];
const createReadStream = () => {
return new Readable({
read() {
console.log('---Readable fn---')
//
// note: the "this" is the readable instance
//
if (madeUpData.length === 0) this.push(null);
else this.push(madeUpData.shift());
},
});
};
function readData(data) {
console.log('got data', data.toString());
}
function endData() {
console.log('finished reading');
}
const readable = createReadStream();
readable.on('data', readData);
readable.on('end', endData);
that will log...
---Readable read fn---
---Readable read fn---
got data <Buffer 73 6f 6d 65>
---Readable read fn---
got data <Buffer 64 61 74 61>
---Readable read fn---
got data <Buffer 74 6f>
---Readable read fn---
got data <Buffer 72 65 61 64>
finished reading
Creating a Readable stream instance with encoding
Notice the note on the setEncoding property of the Readable
function arg object property:
const { Readable } = require('stream');
const madeUpData = ['this','is', 'an', 'array', 'of', 'strings'];
const createReadStream = () => {
return new Readable({
encoding: 'utf8',
read() {
console.log('---Readable read fn---');
if (madeUpData.length === 0) this.push(null);
else this.push(madeUpData.shift());
},
});
};
function readData(data) {
console.log('got data', data);
}
function endData() {
console.log('finished reading');
}
const readable = createReadStream();
readable.on('data', readData);
readable.on('end', endData);
A Readable Stream Just For JavaScript
objectMode is a property of Readable streams that we as developers can use to build the stream for parsing js objects using the stream + chunk interface.
const { Readable } = require('stream');
const madeUpData = ['this', 'is', 'an', 'array', 'of', 'strings'];
const createReadStream = () => {
return new Readable({
objectMode: true,
read() {
console.log('---Readable.read()');
if (madeUpData.length === 0) this.push(null);
else this.push(madeUpData.pop());
},
});
};
const dataFn = (data) => {
console.log('got data', data);
};
const endFn = () => {
console.log('finished reading');
};
const readable = createReadStream();
readable.on('data', dataFn);
readable.on('end', endFn);
That will output...
---Readable.read()
---Readable.read()
got data strings
---Readable.read()
got data of
---Readable.read()
got data array
---Readable.read()
got data an
---Readable.read()
got data is
---Readable.read()
got data this
finished reading
A Readable Stream with less code
The Readable
constructor function includes a from
function that takes some data and uses a different api for devs. This ends up feeling like a more concise bit of code than the above Readable
constructor being writting into our own function where a custom implementation of the read()
function is also required.
const { Readable } = require('stream');
const madeUpData = [13,26,43,96];
const dataFn = (data) => {
console.log(`MATH: ${data} * 3 = ${data * 3}`);
};
const endFn = () => {
console.log('finished reading');
};
const streamObj = Readable.from(madeUpData);
streamObj.on('data',dataFn);
streamObj.on('end', endFn);