Lesson 3 of 6
5 min read
Node.js

File System Operations

Read, write, and manipulate files and directories using the fs module

The fs Module

The fs (file system) module provides an API for interacting with the file system. It offers both synchronous and asynchronous methods, as well as a promises-based API.

Reading Files

const fs = require('fs');
const path = require('path');

// Asynchronous (callback-based)
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Error reading file:', err);
    return;
  }
  console.log(data);
});

// Synchronous (blocks execution)
try {
  const data = fs.readFileSync('example.txt', 'utf8');
  console.log(data);
} catch (err) {
  console.error('Error:', err);
}

// Promise-based (recommended)
const fsPromises = require('fs').promises;

async function readFile() {
  try {
    const data = await fsPromises.readFile('example.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error('Error:', err);
  }
}

readFile();

Writing Files

const fs = require('fs').promises;

// Write a new file (overwrites if exists)
async function writeFile() {
  await fs.writeFile('output.txt', 'Hello, Node.js!');
  console.log('File written successfully');
}

// Append to a file
async function appendToFile() {
  await fs.appendFile('log.txt', 'New log entry\n');
  console.log('Content appended');
}

// Write JSON data
async function writeJSON() {
  const data = {
    name: 'John',
    age: 30,
    skills: ['JavaScript', 'Node.js']
  };
  
  await fs.writeFile(
    'data.json', 
    JSON.stringify(data, null, 2)  // Pretty print with 2 spaces
  );
}

writeJSON();

Working with Directories

const fs = require('fs').promises;
const path = require('path');

// Create a directory
async function createDir() {
  await fs.mkdir('new-folder', { recursive: true });
  // recursive: true creates parent directories if needed
}

// Read directory contents
async function listFiles() {
  const files = await fs.readdir('.');
  console.log('Files:', files);
  
  // With file type information
  const entries = await fs.readdir('.', { withFileTypes: true });
  entries.forEach(entry => {
    const type = entry.isDirectory() ? 'DIR' : 'FILE';
    console.log(`[${type}] ${entry.name}`);
  });
}

// Remove a directory
async function removeDir() {
  await fs.rmdir('old-folder', { recursive: true });
}

// Check if file/directory exists
async function checkExists(filePath) {
  try {
    await fs.access(filePath);
    return true;
  } catch {
    return false;
  }
}

File Information & Stats

const fs = require('fs').promises;

async function getFileInfo(filePath) {
  const stats = await fs.stat(filePath);
  
  console.log('Is file:', stats.isFile());
  console.log('Is directory:', stats.isDirectory());
  console.log('File size:', stats.size, 'bytes');
  console.log('Created:', stats.birthtime);
  console.log('Modified:', stats.mtime);
}

getFileInfo('package.json');

Copying, Moving & Deleting

const fs = require('fs').promises;

// Copy a file
async function copyFile() {
  await fs.copyFile('source.txt', 'destination.txt');
}

// Rename/Move a file
async function moveFile() {
  await fs.rename('old-name.txt', 'new-name.txt');
  // Also works for moving to different directory
  await fs.rename('file.txt', 'subfolder/file.txt');
}

// Delete a file
async function deleteFile() {
  await fs.unlink('unwanted-file.txt');
}

The path Module

Use the path module for cross-platform path handling:

const path = require('path');

// Join path segments
const fullPath = path.join(__dirname, 'data', 'file.txt');
// /Users/you/project/data/file.txt

// Get file extension
console.log(path.extname('image.png'));  // .png

// Get filename
console.log(path.basename('/path/to/file.txt'));       // file.txt
console.log(path.basename('/path/to/file.txt', '.txt')); // file

// Get directory name
console.log(path.dirname('/path/to/file.txt'));  // /path/to

// Parse path into components
const parsed = path.parse('/home/user/file.txt');
console.log(parsed);
// { root: '/', dir: '/home/user', base: 'file.txt', ext: '.txt', name: 'file' }

// Resolve to absolute path
console.log(path.resolve('data', 'file.txt'));
// /Users/you/project/data/file.txt

Practical Example: File Processor

const fs = require('fs').promises;
const path = require('path');

async function processFiles(directory) {
  const entries = await fs.readdir(directory, { withFileTypes: true });
  
  for (const entry of entries) {
    const fullPath = path.join(directory, entry.name);
    
    if (entry.isDirectory()) {
      // Recursively process subdirectories
      await processFiles(fullPath);
    } else if (entry.name.endsWith('.txt')) {
      // Process text files
      const content = await fs.readFile(fullPath, 'utf8');
      const wordCount = content.split(/\s+/).length;
      console.log(`${entry.name}: ${wordCount} words`);
    }
  }
}

processFiles('./documents');

💡 Best Practices

  • • Use the promises API (fs.promises) for cleaner async code
  • • Always use path.join() for cross-platform compatibility
  • • Handle errors properly with try/catch
  • • Use { recursive: true } when creating nested directories
  • • Consider using streams for large files

Continue Learning