Node.js File System
Node.js - File System (fs module)
Section titled “Node.js - File System (fs module)”Node.js provides a built-in module called fs (File System) for interacting with the file system on the operating system. It allows you to read, write, update, delete, and manage files and directories.
The fs module can be imported using require:
const fs = require('fs');Alternatively, for promise-based operations (recommended for modern async code):
const fsPromises = require('fs').promises;// or using destructuring:const { readFile, writeFile } = require('fs').promises;Synchronous vs. Asynchronous Operations
Section titled “Synchronous vs. Asynchronous Operations”Most methods in the fs module have both synchronous and asynchronous forms.
- Asynchronous methods (e.g.,
fs.readFile(),fs.writeFile()): These methods perform the operation in the background without blocking the Node.js event loop. They typically accept a callback function as the last argument, which is executed upon completion (or error). The first argument to the callback is usually an error object (nullif successful). This is the preferred approach for I/O operations in Node.js servers to maintain concurrency and responsiveness. - Synchronous methods (e.g.,
fs.readFileSync(),fs.writeFileSync()): These methods block the entire Node.js process until the file operation completes. While simpler for scripting or command-line tools, avoid using synchronous methods in web servers or applications that handle concurrent requests, as they will halt execution and severely impact performance. - Promise-based methods (
fs.promises): These provide an alternative asynchronous interface using JavaScript Promises, often used withasync/awaitsyntax for cleaner asynchronous code compared to nested callbacks. Example:await fsPromises.readFile(...).
Example: Reading a File (Async vs Sync)
Section titled “Example: Reading a File (Async vs Sync)”First, create a text file named input.txt with the following content:
Node.js FundamentalsLearning about the file system module.Now, create a JavaScript file named main.js:
const fs = require('fs');
// Asynchronous read using callbackconsole.log('Starting asynchronous read...');fs.readFile('input.txt', 'utf8', (err, data) => { if (err) { console.error('Error reading file asynchronously:', err); return; } console.log('Asynchronous Read Content:\n' + data);});console.log('... Asynchronous read initiated, continuing execution ...');
// Synchronous readconsole.log('\nStarting synchronous read...');try { const dataSync = fs.readFileSync('input.txt', 'utf8'); console.log('Synchronous Read Content:\n' + dataSync);} catch (err) { console.error('Error reading file synchronously:', err);}console.log('... Synchronous read finished ...');
console.log('\nProgram Ended');Run the script:
$ node main.jsExpected Output (order might vary slightly for async part):
Starting asynchronous read...... Asynchronous read initiated, continuing execution ...
Starting synchronous read...Synchronous Read Content:Node.js FundamentalsLearning about the file system module.... Synchronous read finished ...
Program EndedAsynchronous Read Content:Node.js FundamentalsLearning about the file system module.Notice how ‘continuing execution’ and the synchronous read logs appear before the asynchronous read content. This demonstrates the non-blocking nature of asynchronous operations.
Common File System Operations
Section titled “Common File System Operations”Let’s explore some key fs methods using asynchronous examples with callbacks. Remember that promise-based versions (fs.promises) are often preferred in modern code.
Opening a File (fs.open)
Section titled “Opening a File (fs.open)”Syntax: fs.open(path, flags[, mode], callback)
path: Path to the file.flags: Specifies how the file should be opened (e.g., ‘r’ for read, ‘w’ for write, ‘a’ for append). See table below.mode(optional): Sets file permissions if the file is created (default: 0o666).callback: Function called with(err, fd), wherefdis the file descriptor (a number representing the opened file).
Common Flags:
Section titled “Common Flags:”| Flag | Description |
|---|---|
'r' | Open file for reading. An error occurs if the file does not exist. |
'r+' | Open file for reading and writing. An error occurs if the file does not exist. |
'w' | Open file for writing. The file is created (if it does not exist) or truncated (if it exists). |
'w+' | Open file for reading and writing. Created or truncated. |
'a' | Open file for appending. The file is created if it does not exist. |
'a+' | Open file for reading and appending. Created if non-existent. |
Example:
const fs = require('fs');
console.log('Going to open input.txt for reading...');fs.open('input.txt', 'r', (err, fd) => { if (err) { return console.error('Error opening file:', err); } console.log('File opened successfully! File descriptor:', fd);
// Remember to close the file descriptor when done fs.close(fd, (closeErr) => { if (closeErr) { console.error('Error closing file:', closeErr); } console.log('File closed successfully.'); });});Note: Using higher-level functions like fs.readFile or fs.writeFile is often simpler as they handle opening and closing the file automatically.
Getting File Information (fs.stat)
Section titled “Getting File Information (fs.stat)”Syntax: fs.stat(path, callback)
path: Path to the file or directory.callback: Function called with(err, stats), wherestatsis anfs.Statsobject containing file details.
The stats object has useful properties (like size, mtime) and methods:
| Method | Description |
|---|---|
stats.isFile() | Returns true if it’s a regular file. |
stats.isDirectory() | Returns true if it’s a directory. |
stats.isSymbolicLink() | Returns true if it’s a symbolic link. |
Example:
const fs = require('fs');
console.log('Getting information for input.txt...');fs.stat('input.txt', (err, stats) => { if (err) { return console.error('Error getting file stats:', err); } console.log('File Stats:', stats); console.log('\nIs File?', stats.isFile()); console.log('Is Directory?', stats.isDirectory()); console.log('Size:', stats.size, 'bytes'); console.log('Last Modified:', stats.mtime);});Writing to a File (fs.writeFile)
Section titled “Writing to a File (fs.writeFile)”Syntax: fs.writeFile(file, data[, options], callback)
file: Path to the file.data: The data to write (String, Buffer, TypedArray, DataView).options(optional): Can be an encoding string (default ‘utf8’) or an object{ encoding, mode, flag }(default flag ‘w’).callback: Function called with(err)upon completion.
This method overwrites the file if it exists. Use flag 'a' (or fs.appendFile) to append.
Example:
const fs = require('fs');const content = 'Writing some data using fs.writeFile!';
console.log('Going to write to output.txt');fs.writeFile('output.txt', content, 'utf8', (err) => { if (err) { return console.error('Error writing file:', err); } console.log('Data written successfully!');
// Verify by reading back fs.readFile('output.txt', 'utf8', (readErr, data) => { if (readErr) { return console.error('Error reading back file:', readErr); } console.log('Read back content: ' + data); });});Reading from a File (fs.readFile)
Section titled “Reading from a File (fs.readFile)”Syntax: fs.readFile(path[, options], callback)
path: Path to the file.options(optional): Can be an encoding string (e.g., ‘utf8’) or an object{ encoding, flag }. If encoding is provided,datain the callback will be a string; otherwise, it’s a Buffer.callback: Function called with(err, data).
Example (revisiting the earlier async example):
const fs = require('fs');
console.log('Going to read input.txt');fs.readFile('input.txt', 'utf8', (err, data) => { if (err) { return console.error('Error reading file:', err); } console.log('File content:\n' + data);});Using Buffers
Section titled “Using Buffers”If you omit the encoding, readFile returns a Buffer. Buffers are Node.js’s way of handling binary data.
const fs = require('fs');
fs.readFile('input.txt', (err, dataBuffer) => { // No encoding specified if (err) { return console.error(err); } console.log('Data as Buffer:', dataBuffer); console.log('Data as String:', dataBuffer.toString('utf8'));
// Create Buffers directly (modern way) const bufFromArray = Buffer.from([0x68, 0x65, 0x6c, 0x6c, 0x6f]); // from byte array console.log(bufFromArray.toString()); // Output: hello
const bufFromString = Buffer.from('world', 'utf8'); console.log(bufFromString);});Note: The old new Buffer() constructor is deprecated due to security concerns. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead.
Deleting a File (fs.unlink)
Section titled “Deleting a File (fs.unlink)”Syntax: fs.unlink(path, callback)
path: Path to the file to delete.callback: Function called with(err).
Example (use with caution!):
const fs = require('fs');
// First, create a file to deletefs.writeFile('temp_to_delete.txt', 'Delete me', (err) => { if (err) return console.error('Error creating temp file:', err); console.log('Temporary file created.');
// Now delete it console.log('Going to delete temp_to_delete.txt'); fs.unlink('temp_to_delete.txt', (unlinkErr) => { if (unlinkErr) { return console.error('Error deleting file:', unlinkErr); } console.log('File deleted successfully!'); });});Directory Operations
Section titled “Directory Operations”Creating a Directory (fs.mkdir)
Section titled “Creating a Directory (fs.mkdir)”Syntax: fs.mkdir(path[, options], callback)
path: Path of the directory to create.options(optional): Can be mode (permissions, default 0o777) or an object{ recursive, mode }.recursive: trueallows creating parent directories if needed (likemkdir -p).callback: Function called with(err).
Example:
const fs = require('fs');const path = require('path'); // Use path module for cross-platform compatibility
const dirPath = path.join('.', 'my_new_directory', 'nested'); // Creates './my_new_directory/nested'
console.log(`Going to create directory: ${dirPath}`);// Use { recursive: true } to create parent directories as neededfs.mkdir(dirPath, { recursive: true }, (err) => { if (err) { return console.error('Error creating directory:', err); } console.log('Directory created successfully!');});Reading a Directory (fs.readdir)
Section titled “Reading a Directory (fs.readdir)”Syntax: fs.readdir(path[, options], callback)
path: Path of the directory to read.options(optional): Encoding (default ‘utf8’) or object{ encoding, withFileTypes }.withFileTypes: truereturnsfs.Direntobjects instead of just filenames.callback: Function called with(err, files), wherefilesis an array of filenames (strings) orfs.Direntobjects.
Example:
const fs = require('fs');
console.log('Going to read contents of current directory (.)');fs.readdir('.', { withFileTypes: true }, (err, files) => { if (err) { return console.error('Error reading directory:', err); } console.log('\nDirectory Contents:'); files.forEach(dirent => { const type = dirent.isDirectory() ? 'Dir' : 'File'; console.log(` - ${dirent.name} (${type})`); });});Removing a Directory (fs.rmdir or fs.rm)
Section titled “Removing a Directory (fs.rmdir or fs.rm)”Syntax (fs.rmdir - older, for empty dirs): fs.rmdir(path, callback)
Syntax (fs.rm - newer, recommended): fs.rm(path[, options], callback)
path: Path of the directory to remove.options(forfs.rm): Object like{ recursive, force }.recursive: trueallows removing non-empty directories.callback: Function called with(err).
Example (using fs.rm):
const fs = require('fs');const path = require('path');
const dirToRemove = path.join('.', 'my_new_directory');
console.log(`Going to remove directory: ${dirToRemove}`);// Use { recursive: true, force: true } to remove non-empty directory// Use force with caution, it suppresses some errors.fs.rm(dirToRemove, { recursive: true }, (err) => { if (err) { // Check if error is because the directory doesn't exist (might be ok) if (err.code === 'ENOENT') { console.log('Directory does not exist, nothing to remove.'); } else { return console.error('Error removing directory:', err); } } else { console.log('Directory removed successfully!'); }});Further Reading
Section titled “Further Reading”The fs module contains many more functions for file system interaction (renaming, changing permissions, watching for changes, etc.). Refer to the official Node.js documentation for a complete list and detailed descriptions:
- Node.js File System API Docs: https://nodejs.org/api/fs.html