Exploring Directories in Node.js
Basic Setup and Installation
First, create a new Node.js project and ensure it supports ES modules by adding this to your package.json:
1 {2 "type": "module"3 }
Create two files:
- fileExplorer.js - Contains the core functionality
- main.js - Contains usage examples
Core Implementation (fileExplorer.js)
1 import { promises as fsPromises } from "fs";2 import { extname, join } from "path";34 // Main function to get files and directories5 export async function getFilesAndDirs(dirPath, options = {}) {6 const { recursive = false, filePattern = null, dirPattern = null } = options;78 const result = {9 files: [],10 directories: [],11 };1213 try {14 const entries = await fsPromises.readdir(dirPath, { withFileTypes: true });1516 for (const entry of entries) {17 const fullPath = join(dirPath, entry.name);1819 if (entry.isDirectory()) {20 if (!dirPattern || dirPattern.test(entry.name)) {21 result.directories.push(fullPath);22 }2324 if (recursive) {25 const subResults = await getFilesAndDirs(fullPath, options);26 result.files.push(...subResults.files);27 result.directories.push(...subResults.directories);28 }29 } else if (entry.isFile()) {30 if (!filePattern || filePattern.test(entry.name)) {31 result.files.push(fullPath);32 }33 }34 }3536 return result;37 } catch (error) {38 throw new Error(`Failed to read directory: ${error.message}`);39 }40 }4142 // Get detailed file information43 export async function getDetailedInfo(dirPath) {44 try {45 const entries = await fsPromises.readdir(dirPath, { withFileTypes: true });46 const result = {47 files: [],48 directories: [],49 };5051 for (const entry of entries) {52 const fullPath = join(dirPath, entry.name);53 const stats = await fsPromises.stat(fullPath);5455 const baseInfo = {56 name: entry.name,57 path: fullPath,58 size: stats.size,59 created: stats.birthtime,60 modified: stats.mtime,61 };6263 if (entry.isDirectory()) {64 result.directories.push({65 ...baseInfo,66 type: "directory",67 });68 } else if (entry.isFile()) {69 result.files.push({70 ...baseInfo,71 type: "file",72 extension: extname(entry.name),73 });74 }75 }7677 return result;78 } catch (error) {79 throw new Error(`Failed to get detailed information: ${error.message}`);80 }81 }8283 // File size formatter utility84 export function formatFileSize(bytes) {85 const sizes = ["Bytes", "KB", "MB", "GB", "TB"];86 if (bytes === 0) return "0 Bytes";87 const i = Math.floor(Math.log(bytes) / Math.log(1024));88 return `${Math.round(bytes / Math.pow(1024, i))} ${sizes[i]}`;89 }9091 // Utility functions92 export const utils = {93 createFilePattern: (...extensions) => {94 const pattern = extensions95 .map((ext) => `\\.${ext.replace(/^\./, "")}`)96 .join("|");97 return new RegExp(`(${pattern})$`);98 },99100 async isAccessible(path) {101 try {102 await fsPromises.access(path);103 return true;104 } catch {105 return false;106 }107 },108 };
Usage Examples (main.js)
1 import {2 formatFileSize,3 getDetailedInfo,4 getFilesAndDirs,5 utils,6 } from "./fileExplorer.js";78 // Basic directory scanning9 async function basicExample() {10 try {11 const result = await getFilesAndDirs("./my-directory");12 console.log("Files:", result.files);13 console.log("Directories:", result.directories);14 } catch (error) {15 console.error("Error:", error.message);16 }17 }1819 // Recursive scanning with filters20 async function advancedExample() {21 try {22 const result = await getFilesAndDirs("./my-directory", {23 recursive: true,24 filePattern: utils.createFilePattern("js", "ts"), // Only JavaScript and TypeScript files25 dirPattern: /^(?!node_modules).*/, // Exclude node_modules directory26 });27 console.log("JavaScript and TypeScript files:", result.files);28 } catch (error) {29 console.error("Error:", error.message);30 }31 }3233 // Getting detailed file information34 async function detailedExample() {35 try {36 const details = await getDetailedInfo("./my-directory");37 details.files.forEach((file) => {38 console.log(`39 File: ${file.name}40 Size: ${formatFileSize(file.size)}41 Created: ${file.created}42 Modified: ${file.modified}43 Extension: ${file.extension}44 `);45 });46 } catch (error) {47 console.error("Error:", error.message);48 }49 }5051 // Run all examples52 async function runExamples() {53 console.log("--- Basic Example ---");54 await basicExample();5556 console.log("\n--- Advanced Example ---");57 await advancedExample();5859 console.log("\n--- Detailed Example ---");60 await detailedExample();61 }6263 runExamples();
Common Use Cases
1. List All JavaScript Files
1 const jsFiles = await getFilesAndDirs("./src", {2 recursive: true,3 filePattern: /\.js$/,4 });5 console.log("JavaScript files:", jsFiles.files);
2. Get Size of All Images
1 const imagePattern = utils.createFilePattern("jpg", "png", "gif");2 const details = await getDetailedInfo("./images");3 const totalSize = details.files4 .filter((file) => imagePattern.test(file.name))5 .reduce((total, file) => total + file.size, 0);67 console.log("Total image size:", formatFileSize(totalSize));
3. Find Large Files
1 const details = await getDetailedInfo("./");2 const largeFiles = details.files3 .filter((file) => file.size > 1024 * 1024) // Files larger than 1MB4 .sort((a, b) => b.size - a.size);56 largeFiles.forEach((file) => {7 console.log(`${file.name}: ${formatFileSize(file.size)}`);8 });
4. Check for Empty Directories
1 async function findEmptyDirs(dirPath) {2 const result = await getFilesAndDirs(dirPath, { recursive: true });3 const emptyDirs = [];45 for (const dir of result.directories) {6 const contents = await getFilesAndDirs(dir);7 if (contents.files.length === 0 && contents.directories.length === 0) {8 emptyDirs.push(dir);9 }10 }1112 return emptyDirs;13 }
Error Handling Examples
1 async function safeDirectoryOperation(dirPath) {2 try {3 // Check if directory exists and is accessible4 const isAccessible = await utils.isAccessible(dirPath);5 if (!isAccessible) {6 throw new Error("Directory is not accessible");7 }89 const result = await getFilesAndDirs(dirPath, {10 recursive: true,11 });1213 return result;14 } catch (error) {15 if (error.code === "ENOENT") {16 console.error("Directory does not exist:", dirPath);17 } else if (error.code === "EACCES") {18 console.error("Permission denied:", dirPath);19 } else {20 console.error("Unexpected error:", error.message);21 }22 return null;23 }24 }
Best Practices
- Always use try-catch blocks for error handling
- Use the utility functions for consistent patterns
- Consider memory usage with recursive operations
- Check directory accessibility before operations
- Use async/await for cleaner code
- Format file sizes for better readability
Remember to handle errors appropriately and consider performance implications when dealing with large directories or deep recursive operations.