Streams in Node.js are objects that enable the reading and writing of data in a continuous, sequential manner. Unlike traditional methods that involve loading the entire data set into memory, streams process data piece by piece, which is much more efficient and scalable, especially for large amounts of data.
There are four main types of streams in Node.js:
1. Readable Streams: Streams from which data can be read, such as file streams or incoming network data.
2. Writable Streams: Streams to which data can be written, such as a file you’re writing to or an HTTP response.
3. Duplex Streams: Streams that can both read and write data, such as a network socket.
4. Transform Streams: Duplex streams that modify or transform the data as it is read or written, such as data
compression or encryption.
Readable streams allow you to consume data from a source, such as a file or network request, one chunk at a time. Here’s an example of reading a file using a readable stream:
const fs = require('fs'); const readableStream = fs.createReadStream('largeFile.txt', 'utf8'); readableStream.on('data', (chunk) => { console.log('Received chunk:', chunk); }); readableStream.on('end', () => { console.log('File reading completed.'); });
Writable streams allow you to send data to a destination in a controlled manner. Here’s an example of writing data to a file using a writable stream:
const fs = require('fs'); const writableStream = fs.createWriteStream('output.txt'); writableStream.write('Hello, world!\n'); writableStream.write('Writing more data to the file.\n'); writableStream.end(() => { console.log('Finished writing to the file.'); });
One of the most powerful features of Node.js streams is the ability to pipe them together, enabling you to pass data from one stream directly into another. This is particularly useful for tasks like file compression or data transformation:
const fs = require('fs'); const zlib = require('zlib'); const readableStream = fs.createReadStream('input.txt'); const writableStream = fs.createWriteStream('input.txt.gz'); const gzip = zlib.createGzip(); readableStream.pipe(gzip).pipe(writableStream); writableStream.on('finish', () => { console.log('File successfully compressed.'); });
Error handling is critical when working with streams, as data flow might be interrupted by issues such as network failures or file access errors. You can handle errors by listening to the error
event:
const readableStream = fs.createReadStream('nonexistentFile.txt'); readableStream.on('error', (err) => { console.error('An error occurred:', err.message); });