Build a Simple File Compressor with Node.js in 10 Minutes

Have you ever wondered how file compression works? Let's build a simple command-line tool with Node.js that can compress and decompress files. This beginner-friendly project will teach you about streams, one of Node's most powerful features, without overwhelming you with details. What You'll Need Node.js installed on your computer Basic JavaScript knowledge A text editor Project Setup First, create a new folder and set up your project: mkdir file-compressor cd file-compressor npm init -y npm install readline-sync We're using just one package called readline-sync to make it easier to get user input. The Code: Step by Step Create a file called index.js and let's build our compressor piece by piece: Step 1: Import what we need // Import the modules we need const fs = require('fs'); // For working with files const zlib = require('zlib'); // For compression const path = require('path'); // For handling file paths const readlineSync = require('readline-sync'); // For user input // Show a welcome message console.log('==== File Compressor ===='); Step 2: Create our menu // Ask the user what they want to do const choice = readlineSync.question('Do you want to (c)ompress or (d)ecompress a file? '); if (choice.toLowerCase() === 'c') { compressFile(); } else if (choice.toLowerCase() === 'd') { decompressFile(); } else { console.log('Invalid choice. Please enter "c" or "d".'); } Step 3: Create the compression function function compressFile() { // Ask for the file to compress const inputPath = readlineSync.question('Enter the path of the file to compress: '); // Check if the file exists if (!fs.existsSync(inputPath)) { console.log('That file doesn\'t exist. Please check the path and try again.'); return; } // Create output filename const outputPath = inputPath + '.gz'; console.log('Starting compression...'); // Set up our file processing pipeline const readStream = fs.createReadStream(inputPath); const writeStream = fs.createWriteStream(outputPath); const gzip = zlib.createGzip(); // Connect everything together readStream .pipe(gzip) .pipe(writeStream) .on('finish', () => { // Show results when done const originalSize = fs.statSync(inputPath).size; const compressedSize = fs.statSync(outputPath).size; const percentage = ((1 - compressedSize / originalSize) * 100).toFixed(2); console.log('\nCompression complete!'); console.log(`Original size: ${formatSize(originalSize)}`); console.log(`Compressed size: ${formatSize(compressedSize)}`); console.log(`You saved: ${percentage}% of space`); }) .on('error', (err) => { console.log('Something went wrong:', err.message); }); } Step 4: Create the decompression function function decompressFile() { // Ask for the file to decompress const inputPath = readlineSync.question('Enter the path of the compressed file: '); // Check if the file exists if (!fs.existsSync(inputPath)) { console.log('That file doesn\'t exist. Please check the path and try again.'); return; } // Create output filename (remove .gz if present) let outputPath = inputPath.endsWith('.gz') ? inputPath.slice(0, -3) : inputPath + '.decompressed'; console.log('Starting decompression...'); // Set up our file processing pipeline const readStream = fs.createReadStream(inputPath); const writeStream = fs.createWriteStream(outputPath); const gunzip = zlib.createGunzip(); // Connect everything together readStream .pipe(gunzip) .pipe(writeStream) .on('finish', () => { console.log('\nDecompression complete!'); console.log(`Output file: ${outputPath}`); }) .on('error', (err) => { console.log('Something went wrong:', err.message); console.log('This might not be a valid compressed file.'); }); } Step 5: Add a helper function for formatting file sizes // Helper function to format file sizes function formatSize(bytes) { if (bytes

Apr 16, 2025 - 21:41
 0
Build a Simple File Compressor with Node.js in 10 Minutes

Have you ever wondered how file compression works? Let's build a simple command-line tool with Node.js that can compress and decompress files. This beginner-friendly project will teach you about streams, one of Node's most powerful features, without overwhelming you with details.

What You'll Need

  • Node.js installed on your computer
  • Basic JavaScript knowledge
  • A text editor

Image description

Project Setup

First, create a new folder and set up your project:

mkdir file-compressor
cd file-compressor
npm init -y
npm install readline-sync

We're using just one package called readline-sync to make it easier to get user input.

The Code: Step by Step

Create a file called index.js and let's build our compressor piece by piece:

Step 1: Import what we need

// Import the modules we need
const fs = require('fs');          // For working with files
const zlib = require('zlib');      // For compression
const path = require('path');      // For handling file paths
const readlineSync = require('readline-sync'); // For user input

// Show a welcome message
console.log('==== File Compressor ====');

Step 2: Create our menu

// Ask the user what they want to do
const choice = readlineSync.question('Do you want to (c)ompress or (d)ecompress a file? ');

if (choice.toLowerCase() === 'c') {
  compressFile();
} else if (choice.toLowerCase() === 'd') {
  decompressFile();
} else {
  console.log('Invalid choice. Please enter "c" or "d".');
}

Step 3: Create the compression function

function compressFile() {
  // Ask for the file to compress
  const inputPath = readlineSync.question('Enter the path of the file to compress: ');

  // Check if the file exists
  if (!fs.existsSync(inputPath)) {
    console.log('That file doesn\'t exist. Please check the path and try again.');
    return;
  }

  // Create output filename
  const outputPath = inputPath + '.gz';

  console.log('Starting compression...');

  // Set up our file processing pipeline
  const readStream = fs.createReadStream(inputPath);
  const writeStream = fs.createWriteStream(outputPath);
  const gzip = zlib.createGzip();

  // Connect everything together
  readStream
    .pipe(gzip)
    .pipe(writeStream)
    .on('finish', () => {
      // Show results when done
      const originalSize = fs.statSync(inputPath).size;
      const compressedSize = fs.statSync(outputPath).size;
      const percentage = ((1 - compressedSize / originalSize) * 100).toFixed(2);

      console.log('\nCompression complete!');
      console.log(`Original size: ${formatSize(originalSize)}`);
      console.log(`Compressed size: ${formatSize(compressedSize)}`);
      console.log(`You saved: ${percentage}% of space`);
    })
    .on('error', (err) => {
      console.log('Something went wrong:', err.message);
    });
}

Step 4: Create the decompression function

function decompressFile() {
  // Ask for the file to decompress
  const inputPath = readlineSync.question('Enter the path of the compressed file: ');

  // Check if the file exists
  if (!fs.existsSync(inputPath)) {
    console.log('That file doesn\'t exist. Please check the path and try again.');
    return;
  }

  // Create output filename (remove .gz if present)
  let outputPath = inputPath.endsWith('.gz') 
    ? inputPath.slice(0, -3) 
    : inputPath + '.decompressed';

  console.log('Starting decompression...');

  // Set up our file processing pipeline
  const readStream = fs.createReadStream(inputPath);
  const writeStream = fs.createWriteStream(outputPath);
  const gunzip = zlib.createGunzip();

  // Connect everything together
  readStream
    .pipe(gunzip)
    .pipe(writeStream)
    .on('finish', () => {
      console.log('\nDecompression complete!');
      console.log(`Output file: ${outputPath}`);
    })
    .on('error', (err) => {
      console.log('Something went wrong:', err.message);
      console.log('This might not be a valid compressed file.');
    });
}

Step 5: Add a helper function for formatting file sizes

// Helper function to format file sizes
function formatSize(bytes) {
  if (bytes < 1024) {
    return bytes + ' bytes';
  } else if (bytes < 1024 * 1024) {
    return (bytes / 1024).toFixed(2) + ' KB';
  } else {
    return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
  }
}

How to Run Your File Compressor

Save your code and run it with:

node index.js

Follow the prompts to compress or decompress a file. Try compressing a text file first - you'll be amazed at how much smaller it gets!

Understanding Streams: The Key Concept

The magic of this program is in this simple line:

readStream.pipe(gzip).pipe(writeStream)

This creates a pipeline where:

  • readStream reads your file bit by bit
  • Each bit flows through gzip which compresses it
  • The compressed bits flow to writeStream which saves them

Think of it like a water pipe system. The beauty is that you can process files of any size because you're only handling small pieces at a time.

Common Issues You Might Face

  • "File not found" error: Make sure you type the full path to your file
  • Nothing happens after compression: Large files take time to process, be patient
  • The decompressed file doesn't work: Make sure you're decompressing a proper gzip file

What You've Learned

In just a few minutes, you've:

  • Created a useful command-line tool
  • Learned about Node.js streams
  • Used the built-in compression library
  • Processed files efficiently

Now you understand one of the most powerful patterns in Node.js! This same approach works for many other types of file processing.

Next Steps

Once you're comfortable with this code, try:

  • Adding a progress indicator
  • Compressing entire folders
  • Supporting different compression levels

Happy coding!