Readable & Writable Streams
Overview
If a user tries to download a 2-Gigabyte movie from your server, you cannot read the file into memory using fs.readFile. It will consume 2GB of your server's RAM. If 5 users do this, your server crashes instantly. Streams solve this. A Stream reads data in tiny, continuous 'Chunks' (default 64KB Buffers). It reads a chunk, sends it to the user, clears the RAM, and grabs the next chunk. This allows Node to process infinitely massive files while maintaining a tiny, flat memory footprint.
Syntax
const fs = require('fs');
// --- 1. READABLE STREAM (Extracting data slowly) ---
// Opens a pipeline to the file on the hard drive
const readStream = fs.createReadStream('massive_video.mp4');
// It emits 'data' events every time it grabs a 64KB chunk of binary!
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of raw data!`);
});
// Emits when the very last chunk has been successfully read
readStream.on('end', () => console.log('Finished reading file.'));
// --- 2. WRITABLE STREAM (Dumping data slowly) ---
const writeStream = fs.createWriteStream('copy_of_video.mp4');
// You can write data chunks to the stream endlessly!
writeStream.write('Hello ');
writeStream.write('World!\n');
// You MUST explicitly close the stream to save the file!
writeStream.end();Common Pitfalls
- Forgetting to call
.end()on a Writable Stream. If you just call.write(), the stream remains permanently open, waiting for more data. The operating system will not finalize or flush the physical file to the hard drive until it explicitly receives the.end()signal. - Handling errors poorly. Streams are EventEmitters. If a file doesn't exist,
fs.createReadStreamwill NOT throw a synchronous error or a rejected Promise. It will emit an'error'event. If you do not explicitly attach.on('error', ...)to the stream, the unhandled error will violently crash the entire Node process.
Interview Questions
chunk passed into a readable stream's data event by default?By default, Node's fs streams operate with a highWaterMark of exactly 64 Kilobytes (65,536 bytes). It will read and emit exactly 64KB of binary data at a time, keeping RAM usage perfectly stable.
Real-World Example
The classic .pipe() method. This connects a Readable stream DIRECTLY to a Writable stream, automatically flowing the chunks between them without any manual event listeners.
const fs = require('fs');
const readStream = fs.createReadStream('source.txt');
const writeStream = fs.createWriteStream('destination.txt');
// The magical Pipe!
// As chunks are read, they are instantly piped into the writer.
// This is how you copy a 50GB file using only 64KB of RAM!
readStream.pipe(writeStream);Check Your Knowledge
Test your understanding of Readable & Writable Streams with these quick questions.