Node js - Working with Directories

Node.js - Working with Directories

Working with Directories in Node.js

Introduction

Working with directories is a fundamental task in many Node.js applications, including file management systems, log handlers, static file servers, build tools, and more. Node.js provides various ways to interact with directories using built-in modules such as fs, path, and fs/promises. This document covers how to perform a wide range of operations on directories including creating, reading, renaming, deleting, listing contents, checking existence, and navigating between directories.

Understanding how to manage directories programmatically enhances your ability to build robust file-based applications. We will explore both synchronous and asynchronous approaches to give a comprehensive understanding.

Modules Required

fs Module

The fs (File System) module is used to interact with the file system in a traditional callback-based or synchronous manner.

fs/promises Module

Introduced in Node.js 10+, fs/promises enables the use of Promise-based asynchronous file system methods.

path Module

The path module helps in handling and transforming file paths across operating systems.


const fs = require('fs');
const fsPromises = require('fs/promises');
const path = require('path');

Creating a Directory

Asynchronous Method (Callback)


fs.mkdir('new-folder', (err) => {
    if (err) {
        return console.error("Error creating directory:", err);
    }
    console.log('Directory created successfully');
});

Synchronous Method


try {
    fs.mkdirSync('new-folder-sync');
    console.log('Directory created synchronously');
} catch (err) {
    console.error(err);
}

Using fs.promises


async function createDirectory() {
    try {
        await fsPromises.mkdir('new-folder-promises');
        console.log('Directory created using promises');
    } catch (err) {
        console.error(err);
    }
}

createDirectory();

Creating Nested Directories


fs.mkdir('nested/dir/structure', { recursive: true }, (err) => {
    if (err) throw err;
    console.log('Nested directory created');
});

Checking If a Directory Exists

Using fs.existsSync()


if (fs.existsSync('new-folder')) {
    console.log('Directory exists');
} else {
    console.log('Directory does not exist');
}

Using fs.access()


fs.access('new-folder', fs.constants.F_OK, (err) => {
    console.log(err ? 'Does not exist' : 'Exists');
});

Reading Directory Contents

Asynchronous (fs.readdir)


fs.readdir('new-folder', (err, files) => {
    if (err) return console.error(err);
    console.log('Files:', files);
});

Synchronous


try {
    const files = fs.readdirSync('new-folder');
    console.log('Directory contents:', files);
} catch (err) {
    console.error(err);
}

fs.promises Example


async function readDir() {
    try {
        const files = await fsPromises.readdir('new-folder');
        console.log(files);
    } catch (err) {
        console.error(err);
    }
}

readDir();

Renaming a Directory

Using fs.rename()


fs.rename('new-folder', 'renamed-folder', (err) => {
    if (err) return console.error(err);
    console.log('Directory renamed');
});

Synchronous


try {
    fs.renameSync('renamed-folder', 'final-folder');
    console.log('Directory renamed synchronously');
} catch (err) {
    console.error(err);
}

Removing a Directory

fs.rmdir()


fs.rmdir('final-folder', (err) => {
    if (err) return console.error(err);
    console.log('Directory removed');
});

Synchronous


try {
    fs.rmdirSync('final-folder');
    console.log('Directory removed synchronously');
} catch (err) {
    console.error(err);
}

fs.promises.rmdir()


async function deleteDir() {
    try {
        await fsPromises.rmdir('final-folder');
        console.log('Directory deleted');
    } catch (err) {
        console.error(err);
    }
}

deleteDir();

Removing Non-empty Directories (Node 12+)


fs.rm('non-empty-folder', { recursive: true, force: true }, (err) => {
    if (err) throw err;
    console.log('Non-empty directory removed');
});

Working with Paths

Using path.join()


const fullPath = path.join(__dirname, 'dir', 'file.txt');
console.log(fullPath);

path.resolve()


const absolute = path.resolve('dir', 'file.txt');
console.log(absolute);

Changing the Current Working Directory


console.log('Before:', process.cwd());

process.chdir('some-folder');

console.log('After:', process.cwd());

Getting File or Directory Stats


fs.stat('new-folder', (err, stats) => {
    if (err) return console.error(err);
    console.log('Is directory:', stats.isDirectory());
    console.log('Created on:', stats.birthtime);
});

Filtering Files vs Directories


fs.readdir('your-folder', (err, items) => {
    if (err) return console.error(err);

    items.forEach(item => {
        const fullPath = path.join('your-folder', item);

        fs.stat(fullPath, (err, stats) => {
            if (err) return console.error(err);
            if (stats.isDirectory()) {
                console.log(`${item} is a directory`);
            } else {
                console.log(`${item} is a file`);
            }
        });
    });
});

Watching Directories

Use fs.watch() or fs.watchFile() to monitor changes in a directory.


fs.watch('some-folder', (eventType, filename) => {
    console.log(`Event: ${eventType}`);
    console.log(`File changed: ${filename}`);
});

Recursively Reading Directories


function readRecursively(dir) {
    fs.readdir(dir, { withFileTypes: true }, (err, files) => {
        if (err) return console.error(err);

        files.forEach(file => {
            const fullPath = path.join(dir, file.name);
            if (file.isDirectory()) {
                readRecursively(fullPath);
            } else {
                console.log('File:', fullPath);
            }
        });
    });
}

readRecursively('base-folder');

Using Third-Party Libraries

fs-extra


const fsExtra = require('fs-extra');

fsExtra.ensureDir('new-dir')
    .then(() => console.log('Directory ensured'))
    .catch(err => console.error(err));

fsExtra.emptyDir('empty-me')
    .then(() => console.log('Directory emptied'));

glob - Pattern Matching


const glob = require('glob');

glob("**/*.js", function(err, files) {
    if (err) console.error(err);
    else console.log("JavaScript files:", files);
});

Best Practices

  • Always check if directories exist before reading or writing to them
  • Use fs.promises or async/await for clean asynchronous logic
  • Use path.join() for cross-platform file path handling
  • Use try/catch with async/await to properly handle errors
  • Prefer recursive: true for deep directory operations

Common Errors and Troubleshooting

  • ENOENT: No such file or directory - Ensure the path exists
  • EEXIST: Directory already exists - Handle with try/catch or fs.existsSync
  • EPERM: Permission denied - Check user access rights
  • ENOTEMPTY: Directory not empty - Use recursive flag to remove contents

Working with directories in Node.js is a powerful capability that allows developers to automate, manipulate, and interact with the file system efficiently. From creating directories and reading their contents to renaming, removing, and watching for changes, Node.js provides a rich set of tools and APIs.

By mastering both synchronous and asynchronous approaches, leveraging promises for cleaner code, and using modules like fs and path correctly, developers can build robust, file-aware Node.js applications. Furthermore, with the addition of third-party tools like fs-extra and glob, even more advanced functionality becomes easily accessible.

Beginner 5 Hours
Node.js - Working with Directories

Working with Directories in Node.js

Introduction

Working with directories is a fundamental task in many Node.js applications, including file management systems, log handlers, static file servers, build tools, and more. Node.js provides various ways to interact with directories using built-in modules such as fs, path, and fs/promises. This document covers how to perform a wide range of operations on directories including creating, reading, renaming, deleting, listing contents, checking existence, and navigating between directories.

Understanding how to manage directories programmatically enhances your ability to build robust file-based applications. We will explore both synchronous and asynchronous approaches to give a comprehensive understanding.

Modules Required

fs Module

The fs (File System) module is used to interact with the file system in a traditional callback-based or synchronous manner.

fs/promises Module

Introduced in Node.js 10+, fs/promises enables the use of Promise-based asynchronous file system methods.

path Module

The path module helps in handling and transforming file paths across operating systems.

const fs = require('fs'); const fsPromises = require('fs/promises'); const path = require('path');

Creating a Directory

Asynchronous Method (Callback)

fs.mkdir('new-folder', (err) => { if (err) { return console.error("Error creating directory:", err); } console.log('Directory created successfully'); });

Synchronous Method

try { fs.mkdirSync('new-folder-sync'); console.log('Directory created synchronously'); } catch (err) { console.error(err); }

Using fs.promises

async function createDirectory() { try { await fsPromises.mkdir('new-folder-promises'); console.log('Directory created using promises'); } catch (err) { console.error(err); } } createDirectory();

Creating Nested Directories

fs.mkdir('nested/dir/structure', { recursive: true }, (err) => { if (err) throw err; console.log('Nested directory created'); });

Checking If a Directory Exists

Using fs.existsSync()

if (fs.existsSync('new-folder')) { console.log('Directory exists'); } else { console.log('Directory does not exist'); }

Using fs.access()

fs.access('new-folder', fs.constants.F_OK, (err) => { console.log(err ? 'Does not exist' : 'Exists'); });

Reading Directory Contents

Asynchronous (fs.readdir)

fs.readdir('new-folder', (err, files) => { if (err) return console.error(err); console.log('Files:', files); });

Synchronous

try { const files = fs.readdirSync('new-folder'); console.log('Directory contents:', files); } catch (err) { console.error(err); }

fs.promises Example

async function readDir() { try { const files = await fsPromises.readdir('new-folder'); console.log(files); } catch (err) { console.error(err); } } readDir();

Renaming a Directory

Using fs.rename()

fs.rename('new-folder', 'renamed-folder', (err) => { if (err) return console.error(err); console.log('Directory renamed'); });

Synchronous

try { fs.renameSync('renamed-folder', 'final-folder'); console.log('Directory renamed synchronously'); } catch (err) { console.error(err); }

Removing a Directory

fs.rmdir()

fs.rmdir('final-folder', (err) => { if (err) return console.error(err); console.log('Directory removed'); });

Synchronous

try { fs.rmdirSync('final-folder'); console.log('Directory removed synchronously'); } catch (err) { console.error(err); }

fs.promises.rmdir()

async function deleteDir() { try { await fsPromises.rmdir('final-folder'); console.log('Directory deleted'); } catch (err) { console.error(err); } } deleteDir();

Removing Non-empty Directories (Node 12+)

fs.rm('non-empty-folder', { recursive: true, force: true }, (err) => { if (err) throw err; console.log('Non-empty directory removed'); });

Working with Paths

Using path.join()

const fullPath = path.join(__dirname, 'dir', 'file.txt'); console.log(fullPath);

path.resolve()

const absolute = path.resolve('dir', 'file.txt'); console.log(absolute);

Changing the Current Working Directory

console.log('Before:', process.cwd()); process.chdir('some-folder'); console.log('After:', process.cwd());

Getting File or Directory Stats

fs.stat('new-folder', (err, stats) => { if (err) return console.error(err); console.log('Is directory:', stats.isDirectory()); console.log('Created on:', stats.birthtime); });

Filtering Files vs Directories

fs.readdir('your-folder', (err, items) => { if (err) return console.error(err); items.forEach(item => { const fullPath = path.join('your-folder', item); fs.stat(fullPath, (err, stats) => { if (err) return console.error(err); if (stats.isDirectory()) { console.log(`${item} is a directory`); } else { console.log(`${item} is a file`); } }); }); });

Watching Directories

Use fs.watch() or fs.watchFile() to monitor changes in a directory.

fs.watch('some-folder', (eventType, filename) => { console.log(`Event: ${eventType}`); console.log(`File changed: ${filename}`); });

Recursively Reading Directories

function readRecursively(dir) { fs.readdir(dir, { withFileTypes: true }, (err, files) => { if (err) return console.error(err); files.forEach(file => { const fullPath = path.join(dir, file.name); if (file.isDirectory()) { readRecursively(fullPath); } else { console.log('File:', fullPath); } }); }); } readRecursively('base-folder');

Using Third-Party Libraries

fs-extra

const fsExtra = require('fs-extra'); fsExtra.ensureDir('new-dir') .then(() => console.log('Directory ensured')) .catch(err => console.error(err)); fsExtra.emptyDir('empty-me') .then(() => console.log('Directory emptied'));

glob - Pattern Matching

const glob = require('glob'); glob("**/*.js", function(err, files) { if (err) console.error(err); else console.log("JavaScript files:", files); });

Best Practices

  • Always check if directories exist before reading or writing to them
  • Use fs.promises or async/await for clean asynchronous logic
  • Use path.join() for cross-platform file path handling
  • Use try/catch with async/await to properly handle errors
  • Prefer recursive: true for deep directory operations

Common Errors and Troubleshooting

  • ENOENT: No such file or directory - Ensure the path exists
  • EEXIST: Directory already exists - Handle with try/catch or fs.existsSync
  • EPERM: Permission denied - Check user access rights
  • ENOTEMPTY: Directory not empty - Use recursive flag to remove contents

Working with directories in Node.js is a powerful capability that allows developers to automate, manipulate, and interact with the file system efficiently. From creating directories and reading their contents to renaming, removing, and watching for changes, Node.js provides a rich set of tools and APIs.

By mastering both synchronous and asynchronous approaches, leveraging promises for cleaner code, and using modules like fs and path correctly, developers can build robust, file-aware Node.js applications. Furthermore, with the addition of third-party tools like fs-extra and glob, even more advanced functionality becomes easily accessible.

Related Tutorials

Frequently Asked Questions for Node.js

A function passed as an argument and executed later.

Runs multiple instances to utilize multi-core systems.

Reusable blocks of code, exported and imported using require() or import.

nextTick() executes before setImmediate() in the event loop.

Starts a server and listens on specified port.

Node Package Manager β€” installs, manages, and shares JavaScript packages.

A minimal and flexible web application framework for Node.js.

A stream handles reading or writing data continuously.

It processes asynchronous callbacks and non-blocking I/O operations efficiently.

Node.js is a JavaScript runtime built on Chrome's V8 engine for server-side scripting.

An object representing the eventual completion or failure of an asynchronous operation.

require is CommonJS; import is ES6 syntax (requires transpilation or newer versions).

Use module.exports or exports.functionName.

Variables stored outside the code for configuration, accessed using process.env.


MongoDB, often used with Mongoose for schema management.

Describes project details and manages dependencies and scripts.

Synchronous blocks execution; asynchronous runs in background without blocking.

Allows or restricts resources shared between different origins.

Use try-catch, error events, or middleware for error handling.

Provides file system-related operations like read, write, delete.

Using event-driven architecture and non-blocking I/O.

Functions in Express that execute during request-response cycle.

A set of routes or endpoints to interact with server logic or databases.

Yes, it's single-threaded but handles concurrency using the event loop and asynchronous callbacks.

Middleware to parse incoming request bodies, like JSON or form data.

line

Copyrights © 2024 letsupdateskills All rights reserved