Node.js is a powerful platform for building server-side applications using JavaScript. One of its core features is the fs module, which provides an API for interacting with the file system. In this chapter, we'll explore the fs module in depth, covering everything from basic file operations to advanced techniques. By the end of this chapter, you'll have a comprehensive understanding of how to work with the file system in Node.js.
The fs
module in Node.js allows you to work with the file system on your computer. It provides functions for reading, writing, updating, and deleting files, as well as working with directories. The fs
module can be used in both synchronous and asynchronous modes.
To use the fs
module, you need to require it in your Node.js script:
const fs = require('fs');
Synchronous methods block the execution of the code until the operation is completed. While this can be simpler to use, it can also cause performance issues in a production environment.
const fs = require('fs');
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
fs.readFileSync('example.txt', 'utf8')
reads the content of example.txt
in UTF-8 encoding.
// Output //
Content of the example.txt file
Asynchronous methods allow other operations to continue while the file operation is being performed.
const fs = require('fs');
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
console.log(data);
});
fs.readFile('example.txt', 'utf8', callback)
reads the content of example.txt
in UTF-8 encoding.
// Output //
Content of the example.txt file
File streams are useful for reading large files without loading the entire file into memory.
const fs = require('fs');
const readStream = fs.createReadStream('example.txt', 'utf8');
readStream.on('data', (chunk) => {
console.log(chunk);
});
readStream.on('error', (err) => {
console.error(err);
});
readStream.on('end', () => {
console.log('Finished reading the file');
});
fs.createReadStream('example.txt', 'utf8')
creates a readable stream for example.txt
in UTF-8 encoding.data
event is fired whenever a chunk of data is available to read.error
event is fired if an error occurs.end
event is fired when the entire file has been read.
// Output //
Content of the example.txt file
Finished reading the file
Synchronous writing methods block the execution until the operation completes.
const fs = require('fs');
try {
fs.writeFileSync('output.txt', 'Hello, World!', 'utf8');
console.log('File written successfully');
} catch (err) {
console.error(err);
}
fs.writeFileSync('output.txt', 'Hello, World!', 'utf8')
writes the string ‘Hello, World!’ to output.txt
in UTF-8 encoding.
// Output //
File written successfully
Asynchronous writing methods allow other operations to continue while the file operation is being performed.
const fs = require('fs');
fs.writeFile('output.txt', 'Hello, World!', 'utf8', (err) => {
if (err) {
console.error(err);
return;
}
console.log('File written successfully');
});
fs.writeFile('output.txt', 'Hello, World!', 'utf8', callback)
writes the string ‘Hello, World!’ to output.txt
in UTF-8 encoding.
// Output //
File written successfully
File streams are useful for writing large files without loading the entire file into memory.
const fs = require('fs');
const writeStream = fs.createWriteStream('output.txt', 'utf8');
writeStream.write('Hello, ');
writeStream.write('World!');
writeStream.end();
writeStream.on('finish', () => {
console.log('Finished writing to the file');
});
writeStream.on('error', (err) => {
console.error(err);
});
fs.createWriteStream('output.txt', 'utf8')
creates a writable stream for output.txt
in UTF-8 encoding.writeStream.write('Hello, ')
writes ‘Hello, ‘ to the file.writeStream.write('World!')
writes ‘World!’ to the file.writeStream.end()
ends the stream.finish
event is fired when all data has been flushed to the file.error
event is fired if an error occurs.
// Output //
Finished writing to the file
You can create directories using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.mkdirSync('new-directory');
console.log('Directory created successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.mkdir('new-directory', (err) => {
if (err) {
console.error(err);
return;
}
console.log('Directory created successfully');
});
You can remove directories using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.rmdirSync('directory-path');
console.log('Directory removed successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.rmdir('directory-path', (err) => {
if (err) {
console.error(err);
return;
}
console.log('Directory removed successfully');
});
You can check if a file or directory exists using synchronous or asynchronous methods.
const fs = require('fs');
const exists = fs.existsSync('file-or-directory-path');
console.log(exists ? 'Exists' : 'Does not exist');
const fs = require('fs');
fs.access('file-or-directory-path', fs.constants.F_OK, (err) => {
console.log(err ? 'Does not exist' : 'Exists');
});
You can get information about a file or directory using synchronous or asynchronous methods.
const fs = require('fs');
try {
const stats = fs.statSync('file-or-directory-path');
console.log(stats);
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.stat('file-or-directory-path', (err, stats) => {
if (err) {
console.error(err);
return;
}
console.log(stats);
});
You can rename files or directories using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.renameSync('old-path', 'new-path');
console.log('Renamed successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.rename('old-path', 'new-path', (err) => {
if (err) {
console.error(err);
return;
}
console.log('Renamed successfully');
});
You can delete files using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.unlinkSync('file-path');
console.log('File deleted successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.unlink('file-path', (err) => {
if (err) {
console.error(err);
return;
}
console.log('File deleted successfully');
});
You can copy files using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.copyFileSync('source-file', 'destination-file');
console.log('File copied successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.copyFile('source-file', 'destination-file', (err) => {
if (err) {
console.error(err);
return;
}
console.log('File copied successfully');
});
You can change the permissions of a file using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.chmodSync('file-path', 0o755);
console.log('Permissions changed successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.chmod('file-path', 0o755, (err) => {
if (err) {
console.error(err);
return;
}
console.log('Permissions changed successfully');
});
You can change the ownership of a file using synchronous or asynchronous methods.
const fs = require('fs');
try {
fs.chownSync('file-path', uid, gid);
console.log('Ownership changed successfully');
} catch (err) {
console.error(err);
}
const fs = require('fs');
fs.chown('file-path', uid, gid, (err) => {
if (err) {
console.error(err);
return;
}
console.log('Ownership changed successfully');
});
You can watch for changes in files or directories using the fs.watch
method.
const fs = require('fs');
fs.watch('file-or-directory-path', (eventType, filename) => {
if (filename) {
console.log(`${filename} file Changed`);
}
});
fs.watch('file-or-directory-path', callback)
watches for changes in the specified file or directory.eventType
indicates the type of change (e.g., ‘rename’ or ‘change’).filename
is the name of the file that changed.
// Output //
example.txt file Changed
You can use promises with the fs
module for better handling of asynchronous operations.
const fs = require('fs').promises;
async function readFile() {
try {
const data = await fs.readFile('example.txt', 'utf8');
console.log(data);
} catch (err) {
console.error(err);
}
}
readFile();
fs.promises
provides promise-based versions of the fs
module methods.async
function readFile
reads the content of example.txt
in UTF-8 encoding using await fs.readFile
.
// Output //
Content of the example.txt file
Proper error handling is crucial when working with file operations to ensure the application behaves as expected.
const fs = require('fs');
fs.readFile('nonexistent.txt', 'utf8', (err, data) => {
if (err) {
if (err.code === 'ENOENT') {
console.error('File not found');
} else {
console.error(err);
}
return;
}
console.log(data);
});
fs.readFile
method attempts to read nonexistent.txt
.ENOENT
(file not found), it logs ‘File not found’; otherwise, it logs the error.
// Output //
File not found
The fs module in Node.js is a versatile tool for interacting with the file system. It provides a wide range of methods for reading, writing, and manipulating files and directories. By understanding both synchronous and asynchronous operations, as well as advanced topics like file watching and promise-based methods, you can build robust and efficient file system operations in your Node.js applications. This chapter has covered the basics to advanced usage of the fs module, providing you with a solid foundation for working with files in Node.js.Happy coding !❤️