File System Operations
Learn to work with files and directories using Node.js fs module. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
File System Module
The fs module provides an API for interacting with the file system. It supports both synchronous and asynchronous operations, with the asynchronous versions being preferred for better performance.. This is an essential concept that every Node.js developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Reading Files
const fs = require('fs');
// Synchronous file reading
try {
const data = fs.readFileSync('file.txt', 'utf8');
console.log('File content:', data);
} catch (err) {
console.error('Error reading file:', err);
}
// Asynchronous file reading
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) {
console.error('Error reading file:', err);
return;
}
console.log('File content:', data);
});
// Using promises
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('file.txt', 'utf8');
console.log('File content:', data);
} catch (err) {
console.error('Error reading file:', err);
}
}
readFile();
// Reading JSON files
const fs = require('fs').promises;
async function readJSON() {
try {
const data = await fs.readFile('config.json', 'utf8');
const config = JSON.parse(data);
console.log('Config:', config);
} catch (err) {
console.error('Error reading JSON:', err);
}
}
readJSON();Writing Files
const fs = require('fs');
// Synchronous file writing
try {
fs.writeFileSync('output.txt', 'Hello World!');
console.log('File written successfully');
} catch (err) {
console.error('Error writing file:', err);
}
// Asynchronous file writing
fs.writeFile('output.txt', 'Hello World!', (err) => {
if (err) {
console.error('Error writing file:', err);
return;
}
console.log('File written successfully');
});
// Using promises
const fs = require('fs').promises;
async function writeFile() {
try {
await fs.writeFile('output.txt', 'Hello World!');
console.log('File written successfully');
} catch (err) {
console.error('Error writing file:', err);
}
}
writeFile();
// Appending to files
const fs = require('fs').promises;
async function appendToFile() {
try {
await fs.appendFile('log.txt', 'New log entry\n');
console.log('Log entry added');
} catch (err) {
console.error('Error appending to file:', err);
}
}
appendToFile();
// Writing JSON files
const fs = require('fs').promises;
async function writeJSON() {
const data = {
name: 'John Doe',
age: 30,
city: 'New York'
};
try {
await fs.writeFile('user.json', JSON.stringify(data, null, 2));
console.log('JSON file written successfully');
} catch (err) {
console.error('Error writing JSON:', err);
}
}
writeJSON();Directory Operations
const fs = require('fs');
// Creating directories
fs.mkdir('new-directory', (err) => {
if (err) {
console.error('Error creating directory:', err);
return;
}
console.log('Directory created successfully');
});
// Reading directory contents
fs.readdir('.', (err, files) => {
if (err) {
console.error('Error reading directory:', err);
return;
}
console.log('Files in directory:', files);
});
// Checking if file/directory exists
fs.access('file.txt', fs.constants.F_OK, (err) => {
if (err) {
console.log('File does not exist');
} else {
console.log('File exists');
}
});
// Getting file stats
fs.stat('file.txt', (err, stats) => {
if (err) {
console.error('Error getting file stats:', err);
return;
}
console.log('File size:', stats.size);
console.log('Is file:', stats.isFile());
console.log('Is directory:', stats.isDirectory());
console.log('Created:', stats.birthtime);
console.log('Modified:', stats.mtime);
});
// Using promises for directory operations
const fs = require('fs').promises;
async function directoryOperations() {
try {
// Create directory
await fs.mkdir('new-directory');
console.log('Directory created');
// Read directory
const files = await fs.readdir('.');
console.log('Files:', files);
// Check if file exists
try {
await fs.access('file.txt');
console.log('File exists');
} catch {
console.log('File does not exist');
}
// Get file stats
const stats = await fs.stat('file.txt');
console.log('File size:', stats.size);
} catch (err) {
console.error('Error:', err);
}
}
directoryOperations();Advanced File Operations
// Advanced file operations with streams and buffers
const fs = require('fs');
const path = require('path');
// Working with file streams for large files
const readStream = fs.createReadStream('large-file.txt', { encoding: 'utf8' });
const writeStream = fs.createWriteStream('output.txt');
readStream.on('data', (chunk) => {
console.log('Received chunk:', chunk.length, 'bytes');
writeStream.write(chunk);
});
readStream.on('end', () => {
console.log('File reading completed');
writeStream.end();
});
readStream.on('error', (err) => {
console.error('Error reading file:', err);
});
// Working with buffers
const buffer = Buffer.alloc(1024); // Create a 1KB buffer
const buffer2 = Buffer.from('Hello World', 'utf8');
console.log('Buffer length:', buffer.length);
console.log('Buffer content:', buffer2.toString());
// File watching for real-time updates
const watcher = fs.watch('watch-directory', (eventType, filename) => {
console.log(`Event: ${eventType}, File: ${filename}`);
});
// Clean up watcher after 30 seconds
setTimeout(() => {
watcher.close();
console.log('File watcher closed');
}, 30000);
// Working with symbolic links
fs.symlink('target-file.txt', 'link-file.txt', 'file', (err) => {
if (err) {
console.error('Error creating symlink:', err);
} else {
console.log('Symbolic link created');
}
});File System Best Practices
- Use asynchronous methods: Prefer async/await over callbacks for better error handling
- Handle errors properly: Always wrap file operations in try-catch blocks
- Use streams for large files: Avoid loading entire files into memory
- Check file existence: Use fs.access() before operations to avoid errors
- Use path module: Always use path.join() for cross-platform compatibility
- Clean up resources: Close file handles and streams when done
- Use appropriate encoding: Specify encoding when reading text files
- Implement retry logic: For network file systems or unreliable storage
Mini-Project: File Manager CLI
// Create a command-line file manager using Node.js
const fs = require('fs').promises;
const path = require('path');
const readline = require('readline');
class FileManager {
constructor() {
this.currentDir = process.cwd();
this.rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
}
async start() {
console.log('File Manager CLI');
console.log('===============');
console.log(`Current directory: ${this.currentDir}`);
while (true) {
const command = await this.getInput('> ');
await this.executeCommand(command);
}
}
async getInput(prompt) {
return new Promise((resolve) => {
this.rl.question(prompt, resolve);
});
}
async executeCommand(command) {
const [cmd, ...args] = command.trim().split(' ');
try {
switch (cmd.toLowerCase()) {
case 'ls':
case 'list':
await this.listFiles();
break;
case 'cd':
await this.changeDirectory(args[0]);
break;
case 'mkdir':
await this.createDirectory(args[0]);
break;
case 'rm':
await this.removeFile(args[0]);
break;
case 'cat':
await this.readFile(args[0]);
break;
case 'write':
await this.writeFile(args[0], args.slice(1).join(' '));
break;
case 'copy':
await this.copyFile(args[0], args[1]);
break;
case 'move':
await this.moveFile(args[0], args[1]);
break;
case 'info':
await this.fileInfo(args[0]);
break;
case 'find':
await this.findFiles(args[0]);
break;
case 'help':
this.showHelp();
break;
case 'exit':
case 'quit':
console.log('Goodbye!');
this.rl.close();
process.exit(0);
break;
default:
console.log('Unknown command. Type "help" for available commands.');
}
} catch (error) {
console.error('Error:', error.message);
}
}
async listFiles() {
const files = await fs.readdir(this.currentDir);
const fileInfo = await Promise.all(
files.map(async (file) => {
const filePath = path.join(this.currentDir, file);
const stats = await fs.stat(filePath);
return {
name: file,
isDirectory: stats.isDirectory(),
size: stats.size,
modified: stats.mtime
};
})
);
console.log('\nFiles and directories:');
fileInfo.forEach(file => {
const type = file.isDirectory ? '[DIR]' : '[FILE]';
const size = file.isDirectory ? '' : ` (${file.size} bytes)`;
console.log(`${type} ${file.name}${size}`);
});
console.log();
}
async changeDirectory(newDir) {
if (!newDir) {
console.log('Current directory:', this.currentDir);
return;
}
const targetPath = path.resolve(this.currentDir, newDir);
const stats = await fs.stat(targetPath);
if (stats.isDirectory()) {
this.currentDir = targetPath;
console.log('Changed to:', this.currentDir);
} else {
console.log('Not a directory:', newDir);
}
}
async createDirectory(dirName) {
if (!dirName) {
console.log('Please specify directory name');
return;
}
const dirPath = path.join(this.currentDir, dirName);
await fs.mkdir(dirPath);
console.log('Directory created:', dirName);
}
async removeFile(fileName) {
if (!fileName) {
console.log('Please specify file name');
return;
}
const filePath = path.join(this.currentDir, fileName);
const stats = await fs.stat(filePath);
if (stats.isDirectory()) {
await fs.rmdir(filePath);
console.log('Directory removed:', fileName);
} else {
await fs.unlink(filePath);
console.log('File removed:', fileName);
}
}
async readFile(fileName) {
if (!fileName) {
console.log('Please specify file name');
return;
}
const filePath = path.join(this.currentDir, fileName);
const content = await fs.readFile(filePath, 'utf8');
console.log('\nFile content:');
console.log(content);
console.log();
}
async writeFile(fileName, content) {
if (!fileName) {
console.log('Please specify file name');
return;
}
const filePath = path.join(this.currentDir, fileName);
await fs.writeFile(filePath, content);
console.log('File written:', fileName);
}
async copyFile(source, destination) {
if (!source || !destination) {
console.log('Please specify source and destination');
return;
}
const sourcePath = path.join(this.currentDir, source);
const destPath = path.join(this.currentDir, destination);
await fs.copyFile(sourcePath, destPath);
console.log('File copied:', source, '->', destination);
}
async moveFile(source, destination) {
if (!source || !destination) {
console.log('Please specify source and destination');
return;
}
const sourcePath = path.join(this.currentDir, source);
const destPath = path.join(this.currentDir, destination);
await fs.rename(sourcePath, destPath);
console.log('File moved:', source, '->', destination);
}
async fileInfo(fileName) {
if (!fileName) {
console.log('Please specify file name');
return;
}
const filePath = path.join(this.currentDir, fileName);
const stats = await fs.stat(filePath);
console.log('\nFile information:');
console.log('Name:', fileName);
console.log('Type:', stats.isDirectory() ? 'Directory' : 'File');
console.log('Size:', stats.size, 'bytes');
console.log('Created:', stats.birthtime);
console.log('Modified:', stats.mtime);
console.log('Accessed:', stats.atime);
console.log();
}
async findFiles(pattern) {
if (!pattern) {
console.log('Please specify search pattern');
return;
}
const files = await this.searchFiles(this.currentDir, pattern);
console.log('\nFound files:');
files.forEach(file => console.log(file));
console.log();
}
async searchFiles(dir, pattern) {
const files = await fs.readdir(dir);
const results = [];
for (const file of files) {
const filePath = path.join(dir, file);
const stats = await fs.stat(filePath);
if (stats.isDirectory()) {
const subResults = await this.searchFiles(filePath, pattern);
results.push(...subResults);
} else if (file.includes(pattern)) {
results.push(filePath);
}
}
return results;
}
showHelp() {
console.log('\nAvailable commands:');
console.log(' ls, list - List files and directories');
console.log(' cd <dir> - Change directory');
console.log(' mkdir <name> - Create directory');
console.log(' rm <name> - Remove file or directory');
console.log(' cat <file> - Read file content');
console.log(' write <file> <content> - Write to file');
console.log(' copy <src> <dest> - Copy file');
console.log(' move <src> <dest> - Move file');
console.log(' info <file> - Show file information');
console.log(' find <pattern> - Find files');
console.log(' help - Show this help');
console.log(' exit, quit - Exit the program');
console.log();
}
}
// Start the file manager
const fileManager = new FileManager();
fileManager.start().catch(console.error);