The file system module, or simply fs
, allows you to access and interact with the file system on your machine.
Using the fs
module, you can perform actions such as:
- creating files and directories
- modifying files and directories
- deleting files and directories
- reading the content of files and directories
This article teaches you the most common and useful fs
methods. So, without further ado, let's see what those methods are.
How to use fs
The file system module is a core Node.js module. That means that you do not have to install it. The only thing you have to do is to import the fs
module into your file.
Thus, add the following line at the top of your file:
const fs = require('fs');
Now you can call any method from the file system module by using the prefix fs
.
Alternatively, you can import only the methods you want from the fs
API as follows:
const { writeFile, readFile } = require('fs');
However, in this tutorial, you will see the first option used - importing the whole fs
module.
Caveat
For this tutorial, you also need to import the path
module. It is another core Node.js module, and it allows you to work with file and directory paths.
Add the following line in your file, after the import of the fs
module:
const path = require('path');
The path
module is not mandatory to work with the file system module. However, it helps!
Sync vs Async
It's important to note that by default, all the fs
methods are asynchronous. However, you can use the synchronous version by adding Sync
at the end of the method.
For instance, a method such as writeFile
becomes writeFileSync
. Synchronous methods complete the code synchronously, and thus they block the main thread. Blocking the main thread in Node.js is considered bad practice.
As a result, this tutorial uses the asynchronous methods from the file system module.
Write to a file
The first thing you learn is how to write to a file. To write to a file from your Node.js application, you use the method writeFile
.
The method writeFile
takes the following arguments at a minimum:
- the name of the file
- the content
- a callback
If the specified file already exists, it replaces the old content with the content you provide as an argument. If the specified file does not exist, it creates a new file.
After importing the fs
and path
modules, write the following code in your application:
fs.writeFile('content.txt', 'This is my first file!', (err) => {
if (err) {
throw err;
};
process.stdout.write('File created successfully!');
});
The above code creates a new file called content.txt
and adds the text This is my first file!
as the content. The callback function throws the error if there is any. Otherwise, it outputs to the console that the file creation succeeded.
Assuming you named your file fsPractice.js
, go to the terminal and run the command node fsPractice.js
. After you run the command, you should see the new file with the specified content.
There are other variants of "writeFile" such as:
- fs.writeFileSync - writes to the file synchronously
- fsPromises.writeFile - uses the promise based API to write to a file
Check this gist to see how your application should look up to this point.
Read from a file
Before you read from a file, you need to create and store the path to the file. Here is where the path
module comes in handy.
With the join
method from the path
module, you can create the file path as follows:
const filePath = path.join(process.cwd(), 'content.txt');
The first argument, process.cwd()
, returns the current working directory. Now that you have the file path, you can read the content of the file.
Write the following code in your file:
fs.readFile(filePath, (error, content) => {
if (error) throw error;
process.stdout.write(content);
});
The readFile
method takes two arguments at the minimum:
- the path of the file
- a callback
If there is an error, it throws an error. Otherwise, it outputs the file content in the terminal.
If you go to the terminal and run the command node fsPractice.js
, you should see the file content in your terminal.
There are other variants of "readFile" such as:
- fs.readFileSync - writes to the file synchronously
- fsPromises.readFile - uses the promise based API to write to a file
Check this gist to see how your application should look up to this point.
Read a directory's content
Displaying the files inside a directory is quite similar to reading the content of a file.
But, instead of passing the file path, you pass the current working directory (you can pass any other directory).
After that, you pass a callback function to handle the response. Write the following code in your file:
fs.readdir(process.cwd(), (error, files) => {
if (error) throw error;
console.log(files);
});
Up to this point, you only used process.stdout.write
to output stuff to the terminal. However, you can simply use console.log
, like in the above code snippet.
If you run the application, you should get an array with all the files in your directory.
Check this gist to see how your application should look up to this point.
Delete a file
The file system module has a method that allows you to delete files. However, it's important to note that it only works for files and not for directories.
When you call the unlink
method with the file path as an argument, it deletes the file. Add the following code snippet to your file:
fs.unlink(filePath, (error) => {
if (error) throw error;
console.log('File deleted!')
});
If you rerun the code, your file should be deleted!
Check this gist to see how your application should look up to this point.
Create a directory
You can create a directory asynchronously by using the mkdir
method. Write the following piece of code in your file:
fs.mkdir(`${process.cwd()}/myFolder/secondFolder`, { recursive: true }, (err) => {
if (err) throw err;
console.log('Folder created successfully!');
});
Let's take it step by step. First, you want to create a new folder inside the current working directory. As mentioned previously, you can get the current working directory with the cwd()
method from the process
object.
After that, you pass the folder or folders you want to create. However, it does not mean you have to create the new folder/s in the current working directory. You can create them anywhere.
Now, the second parameter is the recursive option. If you do not set it to true you cannot create multiple folders. The above code would give an error if you set the recursive
option to false. Try out to see!
However, if you want to create only one folder, you do not need to set the recursive
option to true.
The following code would work just fine!
fs.mkdir(`${process.cwd()}/myFolder`, (err) => {
if (err) throw err;
console.log('Folder created successfully!');
});
Thus, I want to emphasize the use of recursive
. When you want to create folders inside folders, you need to set it to true. It will create all the folders, even if they do not exist.
On the other hand, if you want to create only one folder, you can leave it to false.
Check this gist to see how your application should look up to this point.
Delete a directory
The logic to delete a directory is similar to creating one. If you look at the code you wrote to create a directory and the one below, you will see similarities.
Thus, write the following code in your file:
fs.rmdir(`${process.cwd()}/myFolder/`, { recursive: true }, (err) => {
if (err) throw err;
console.log('Folder/s deleted successfully!');
});
You use the rmdir
method from the file system module, and you pass the following arguments:
- the directory you want to delete
- the recursive property
- a callback
If you set the recursive
property to true, it deletes the folder and its contents. It's important to note that you need to set it to true if the folder has content inside. Otherwise, you get an error.
The code snippet below only works if the folder is empty:
fs.rmdir(`${process.cwd()}/myFolder/`, (err) => {
if (err) throw err;
console.log('Folder/s deleted successfully!');
});
If you have other files and/or folders inside myFolder
, you get an error if you do not pass { recursive: true }
.
It's important to know when to use the recursive
option and when not to avoid issues.
Check this gist to see how your application should look up to this point.
Rename
Using the fs
module, you can rename both directories and files. The code snippet below shows how you can do it with the rename
method.
// renaming a directory
fs.rename(`${process.cwd()}/myFolder/secondFolder`, `${process.cwd()}/myFolder/newFolder`, (err) => {
if (err) throw err;
console.log('Directory renamed!')
});
// renaming a file
fs.rename(`${process.cwd()}/content.txt`, `${process.cwd()}/newFile.txt`, (err) => {
if (err) throw err;
console.log('File renamed!')
});
You can see that the rename
method takes three arguments:
- the first argument is the existing folder/file
- the second argument is the new name
- a callback
Thus, to rename a file or directory, you need to pass the current file/directory's name and the new name. After you run the application, the name of the directory/file should be updated.
It's important to note that if the new path already exists (e.g. the new name for the file/folder), it will be overwritten. Therefore, be sure you do not overwrite existing files/folders by mistake.
Check this gist to see how your application should look up to this point.
Add content to file
With the file system module, you can also add new content to an existing file. The method appendFile
allows you to do that.
If you compare the two methods writeFile
and appendFile
, you can see that they are similar. You pass the file path, the content and a callback.
fs.appendFile(filePath, '\nNew data to be added!', (err) => {
if (err) throw err;
console.log('New content added!');
});
The code snippet above illustrates how you can add new content to an existing file. If you run the application and open your file, you should see the new content inside.
Check this gist to see how your application should look up to this point.
Conclusion
If you are reading this, it means that now you can:
- create files and directories
- modify files and directories
- delete files and directories
- read the content of files and directories
Well done! However, the file system module is more complex, and I encourage you to check the official documentation. In the official documentation, you can see all the methods.