Nodejs Working With Fs File System Complete Guide
Understanding the Core Concepts of NodeJS Working with fs File System
Node.js Working with fs File System
Node.js provides a robust, non-blocking fs
(File System) module designed to facilitate file operations on the server-side environment seamlessly. The fs
module allows you to perform actions like reading, writing, appending, deleting, and renaming files. This capability is pivotal for backend developers who need to manipulate local storage.
Essential Methods in the fs
Module
Synchronous vs. Asynchronous Operations
Asynchronous Methods: These methods do not block execution. Instead, they take a callback function as their final argument. Examples include:
fs.readFile(path, options, callback)
– Reads the contents of a file asynchronously.fs.writeFile(file, data, options, callback)
– Writes data to a file, overwriting if it already exists.fs.unlink(path, callback)
– Deletes a file asynchronously.fs.rename(oldPath, newPath, callback)
– Renames a file asynchronously.
Synchronous Methods: These methods block execution until the operation completes. They should be used sparingly, especially in production environments, to avoid blocking the event loop. Corresponding synchronous versions of the above methods are:
fs.readFileSync(path, options)
fs.writeFileSync(file, data, options)
fs.unlinkSync(path)
fs.renameSync(oldPath, newPath)
Reading Files
- Using Callbacks:
const fs = require('fs'); const path = './data.txt'; fs.readFile(path, 'utf8', (err, data) => { if (err) throw err; console.log(data); });
- Using Promises (
fs.promises
):const fsp = require('fs/promises'); const path = './data.txt'; async function readFileAsync() { try { const data = await fsp.readFile(path, 'utf8'); console.log(data); } catch (err) { console.error(err); } } readFileAsync();
- Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const path = './data.txt'; const readFile = util.promisify(fs.readFile); async function readFileUtilPromisify() { try { const data = await readFile(path, 'utf8'); console.log(data); } catch (err) { console.error(err); } } readFileUtilPromisify();
- Using Callbacks:
Writing Files
Using Callbacks:
const fs = require('fs'); const path = './output.txt'; const content = 'Hello, world!'; fs.writeFile(path, content, err => { if (err) throw err; console.log('The file has been saved!'); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const path = './output.txt'; const content = 'Hello, world!'; async function writeFileAsync() { try { await fsp.writeFile(path, content); console.log('The file has been saved!'); } catch (err) { console.error(err); } } writeFileAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const path = './output.txt'; const content = 'Hello, world!'; const writeFile = util.promisify(fs.writeFile); async function writeFileUtilPromisify() { try { await writeFile(path, content); console.log('The file has been saved!'); } catch (err) { console.error(err); } } writeFileUtilPromisify();
Appending to Files
Append data to an existing file or create the file if it does not exist.
Using Callbacks:
const fs = require('fs'); const path = './output.txt'; const content = '\nAppended text here!'; fs.appendFile(path, content, 'utf8', err => { if (err) throw err; console.log('The text has been appended!'); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const path = './output.txt'; const content = '\nAppended text here!'; async function appendFileAsync() { try { await fsp.appendFile(path, content, 'utf8'); console.log('The text has been appended!'); } catch (err) { console.error(err); } } appendFileAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const path = './output.txt'; const content = '\nAppended text here!'; const appendFile = util.promisify(fs.appendFile); async function appendFileUtilPromisify() { try { await appendFile(path, content, 'utf8'); console.log('The text has been appended!'); } catch (err) { console.error(err); } } appendFileUtilPromisify();
Deleting (unlinking) Files
The
unlink()
method is used for deleting files.Using Callbacks:
const fs = require('fs'); const path = './output.txt'; fs.unlink(path, err => { if (err) throw err; console.log(` ${path} was deleted`); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const path = './output.txt'; async function deleteFileAsync() { try { await fsp.unlink(path); console.log(`${path} was deleted`); } catch (err) { console.error(err); } } deleteFileAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const path = './output.txt'; const unlink = util.promisify(fs.unlink); async function deleteFileUtilPromisify() { try { await unlink(path); console.log(`${path} was deleted`); } catch (err) { console.error(err); } } deleteFileUtilPromisify();
Renaming Files
Rename a file from one path to another.
Using Callbacks:
const fs = require('fs'); const oldPath = './output-old.txt'; const newPath = './output-new.txt'; fs.rename(oldPath, newPath, err => { if (err) throw err; console.log('Rename complete!'); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const oldPath = './output-old.txt'; const newPath = './output-new.txt'; async function renameFileAsync() { try { await fsp.rename(oldPath, newPath); console.log('Rename complete!'); } catch (err) { console.error(err); } } renameFileAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const oldPath = './output-old.txt'; const newPath = './output-new.txt'; const rename = util.promisify(fs.rename); async function renameFileUtilPromisify() { try { await rename(oldPath, newPath); console.log('Rename complete!'); } catch (err) { console.error(err); } } renameFileUtilPromisify();
Working with Directories
Creating Directories:
Using Callbacks:
const fs = require('fs'); const dirPath = './new-directory'; fs.mkdir(dirPath, { recursive: true }, (err) => { if (err) throw err; console.log('Directory created successfully'); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const dirPath = './new-directory'; async function createDirectoryAsync() { try { await fsp.mkdir(dirPath, { recursive: true }); console.log('Directory created successfully'); } catch (err) { console.error(err); } } createDirectoryAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const dirPath = './new-directory'; const mkdir = util.promisify(fs.mkdir); async function createDirectoryUtilPromisify() { try { await mkdir(dirPath, { recursive: true }); console.log('Directory created successfully'); } catch (err) { console.error(err); } } createDirectoryUtilPromisify();
Reading Directories:
Using Callbacks:
const fs = require('fs'); const dirPath = './'; // Root directory fs.readdir(dirPath, (err, files) => { if (err) throw err; console.log(files); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const dirPath = './'; // Root directory async function readDirectoryAsync() { try { const files = await fsp.readdir(dirPath); console.log(files); } catch (err) { console.error(err); } } readDirectoryAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const dirPath = './'; // Root directory const readdir = util.promisify(fs.readdir); async function readDirectoryUtilPromisify() { try { const files = await readdir(dirPath); console.log(files); } catch (err) { console.error(err); } } readDirectoryUtilPromisify();
Removing Directories:
Using Callbacks:
const fs = require('fs'); const dirPath = './new-directory'; fs.rmdir(dirPath, { recursive: true }, err => { if (err) throw err; console.log(`${dirPath} removed successfully`); });
Using Promises (
fs.promises
):const fsp = require('fs/promises'); const dirPath = './new-directory'; async function removeDirectoryAsync() { try { await fsp.rm(dirPath, { recursive: true, force: true }); console.log(`${dirPath} removed successfully`); } catch (err) { console.error(err); } } removeDirectoryAsync();
Using Async/Await and
util.promisify
:const fs = require('fs'); const util = require('util'); const dirPath = './new-directory'; const rm = util.promisify(fs.rm); async function removeDirectoryUtilPromisify() { try { await rm(dirPath, { recursive: true, force: true }); console.log(`${dirPath} removed successfully`); } catch (err) { console.error(err); } } removeDirectoryUtilPromisify();
Checking File/Directory Existence
Using
fs.exists()
(Deprecated):- It is deprecated and discouraged in favor of checking existence before performing operations.
Checking Existence using Promises:
const fsp = require('fs/promises'); const path = './data.txt'; async function checkFileExists() { try { await fsp.access(path); console.log('File exists'); } catch (err) { console.log('File does not exist'); } } checkFileExists();
Using Callbacks:
const fs = require('fs'); const path = './data.txt'; fs.access(path, fs.constants.F_OK, (err) => { if (err) { console.log('File does not exist'); } else { console.log('File exists'); } });
Watching Files
The
fs.watch()
method watches for changes onfilename
. A listener will be appended to thefilename
.Implementation Example:
const fs = require('fs'); const path = './watch-this-file.txt'; fs.watch(path, (eventType, filename) => { console.log(`Event type is: ${eventType}`); if (filename) { console.log(`Filename provided: ${filename}`); } else { console.log('Filename not provided'); } });
Streamed File I/O
For handling large files effectively, Node.js recommends using streams. Streams are more efficient, particularly for large files, as they allow data to be processed piece by piece rather than loading everything into memory at once.
Reading Files with Streams:
const fs = require('fs'); const path = './large-data.txt'; const readStream = fs.createReadStream(path, 'utf8'); readStream.on('data', chunk => { console.log(chunk); }); readStream.on('end', () => { console.log('Finished reading the file.'); }); readStream.on('error', err => { console.log('An error occurred.', err); });
Writing Files with Streams:
const fs = require('fs'); const writeStream = fs.createWriteStream('output-large-data.txt'); writeStream.write('Here is some data.\n'); writeStream.write('One more line added!\n'); writeStream.end('This is the last line.'); writeStream.on('finish', () => { console.log('File has been written successfully.'); }); writeStream.on('error', err => { console.log('An error occurred.', err); });
Buffered I/O
When working with binary data (like images or any other non-text files), use the Buffer class provided by Node.js.
Example Reading an Image File:
const fs = require('fs');
const path = './image.png';
fs.readFile(path, (err, data) => {
if (err) throw err;
console.log(data); // Logs Buffer object containing the image data
});
Example Writing Binary Data:
const fs = require('fs');
const data = Buffer.from('Some binary data here.');
fs.writeFile('./binary-output.bin', data, err => {
if (err) throw err;
console.log('Binary file has been saved.');
});
Handling Errors Gracefully
It is crucial to handle errors appropriately to ensure that applications remain stable, especially in production environments. Utilize try/catch
blocks when using promises and callbacks to catch and handle any exceptions thrown during file operations.
Example Error Handling While Reading Files:
const fs = require('fs');
const path = './non-existent-file.txt';
fs.readFile(path, 'utf8', (err, data) => {
if (err) {
console.error('Error while reading the file:', err.message);
return;
}
console.log(data);
});
// Using Promises & async/await for more readable code
const fsp = require('fs/promises');
async function safeReadFile() {
try {
const data = await fsp.readFile(path, 'utf8');
console.log(data);
} catch (err) {
console.error('Error while reading the file:', err.message);
}
}
safeReadFile();
Advanced Features: Watching Directories and Chmod
Watching Directories: Similar to watching files, directories can also be monitored for changes.
const fs = require('fs'); const watchDir = fs.watch('./directory-to-watch', (eventType, filename) => { if (filename) { console.log(`event type is: ${eventType}`); console.log(`filename provided: ${filename}`); } else { console.log('filename not provided'); } });
Changing Permissions: Modify file permissions using
chmod()
or its promise-basedchmod()
counterpart infs.promises
.
Online Code run
Step-by-Step Guide: How to Implement NodeJS Working with fs File System
Example 1: Reading a File Synchronously
Step 1: Import the fs
Module
The first step is to include the file system module. You can do this using the require
function.
const fs = require('fs');
Step 2: Use the readFileSync
Method
The readFileSync
method reads the entire content of a file synchronously, meaning it blocks the execution until the file is read.
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
Full Code for Reading a File Synchronously
const fs = require('fs');
try {
// Read the file synchronously
const data = fs.readFileSync('example.txt', 'utf8');
// Log the file contents to the console
console.log('File Contents:', data);
} catch (err) {
// Catch any errors that might occur during reading the file
console.error('Error reading file:', err);
}
Example 2: Reading a File Asynchronously
Step 1: Import the fs
Module
Again, we start by importing the fs
module.
const fs = require('fs');
Step 2: Use the readFile
Method
The readFile
method reads the entire content of a file asynchronously. It requires a callback function to handle the result or error.
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
Full Code for Reading a File Asynchronously
const fs = require('fs');
// Read the file asynchronously
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
// Log any errors that might occur during reading the file
console.error('Error reading file:', err);
return;
}
// Log the file contents to the console
console.log('File Contents:', data);
});
Example 3: Writing a File Synchronously
Step 1: Import the fs
Module
const fs = require('fs');
Step 2: Use the writeFileSync
Method
The writeFileSync
method writes data to a file synchronously, which means it blocks the execution until the data is written.
try {
fs.writeFileSync('output.txt', 'Hello, World!');
console.log('The file has been saved!');
} catch (err) {
console.error(err);
}
Full Code for Writing a File Synchronously
const fs = require('fs');
try {
// Write data to the file synchronously
fs.writeFileSync('output.txt', 'Hello, World!');
// Log success message to console
console.log('The file has been saved!');
} catch (err) {
// Catch and log any errors that occur writing to the file
console.error('Error writing to file:', err);
}
Example 4: Writing a File Asynchronously
Step 1: Import the fs
Module
const fs = require('fs');
Step 2: Use the writeFile
Method
The writeFile
method writes data to a file asynchronously. A callback function should be provided to handle the completion or error.
fs.writeFile('output.txt', 'Hello, World!', (err) => {
if (err) {
console.error(err);
return;
}
console.log('The file has been saved!');
});
Full Code for Writing a File Asynchronously
const fs = require('fs');
// Write data to a file asynchronously
fs.writeFile('output.txt', 'Hello, World!', (err) => {
if (err) {
// Log any errors that might occur writing the file
console.error('Error writing to file:', err);
return;
}
// Log success message to console
console.log('The file has been saved!');
});
Example 5: Checking If a File Exists
Step 1: Import the fs
Module
const fs = require('fs');
Step 2: Using the accessSync
Method (Synchronously)
You can use the accessSync
method to check whether a file exists or not. If the file does not exist, an error will be thrown.
Top 10 Interview Questions & Answers on NodeJS Working with fs File System
Top 10 Questions and Answers: Node.js Working with fs File System
1. What is the fs module in Node.js, and how do you use it?
To use the fs
module, you first need to require it:
const fs = require('fs');
2. How can you read a file asynchronously using fs.readFile?
Reading a file asynchronously prevents your application from blocking while waiting for the file to be read. Use fs.readFile
method for this purpose:
fs.readFile('filename.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
This reads a file named filename.txt
in UTF-8 format and logs its content to the console.
3. How do you handle errors properly when using fs asynchronous methods?
Errors in asynchronous fs
methods are typically handled using callback functions. Always check if an error exists before proceeding:
fs.readFile('filename.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
// Proceed without errors
console.log(data);
});
4. Can you explain the difference between synchronous and asynchronous file operations in Node.js?
In Node.js, fs
module provides both synchronous and asynchronous methods for file operations:
Asynchronous: Methods like
fs.readFile
,fs.writeFile
operate non-blocking. This means the operations do not stop your application from running other code while they are being executed.Synchronous: Methods like
fs.readFileSync
,fs.writeFileSync
stop your application until the operation is completed. Synchronous methods should be avoided in production environments because they can significantly slow down your app if used for time-intensive tasks.
5. How can you write to a file asynchronously in Node.js?
To write to a file asynchronously, use fs.writeFile
method:
fs.writeFile('output.txt', 'Hello, Node.js!', (err) => {
if (err) throw err;
console.log('Data written successfully!');
});
This writes Hello, Node.js!
to a file named output.txt
. If the file does not exist, it will be created.
6. What happens if you write to a file that already exists?
If you use fs.writeFile()
on a file that already exists, its contents will be overwritten by the new data provided.
7. How do you append data to a file in Node.js?
Appending data to a file is done using fs.appendFile
:
fs.appendFile('log.txt', '\nNew line of text', (err) => {
if (err) throw err;
console.log('Data appended to file.');
});
Appending data allows you to add content to the end of a file without overwriting its existing data.
8. How can you check if a file exists in Node.js?
You can use the fs.exists()
method, but it has been deprecated. Instead, you should use fs.access(path, fs.F_OK, callback)
to check file existence:
const fs = require('fs');
fs.access('path/to/file', fs.constants.F_OK, (err) => {
if (err) {
console.log('File does not exist');
return;
}
console.log('File exists');
});
9. How do you delete a file in Node.js?
Deleting a file can be done with the fs.unlink
function:
fs.unlink('path/to/file.txt', (err) => {
if (err) throw err;
console.log('File was deleted.');
});
This asynchronously deletes a file at the specified path.
10. How can I create a directory in Node.js using fs.mkdir?
Creating directories is necessary when organizing saved files. Use the fs.mkdir
function to create a new directory:
fs.mkdir('/path/to/dir', { recursive: true }, (err) => {
if (err) throw err;
console.log('Directory was created successfully!');
});
Setting the recursive
option to true
ensures that no error will be thrown if the directory already exists, and also allows creating nested directories.
Login to post a comment.