Mastering the FS module In NodeJS
Tags: node, javascript, typescript
Published: 2023-07-19 13:57:33

The fs module is part of the built in Modules that comes with NodeJS by default, this module allows you to create and manipulate files and folders with the drop of a hat and this module is going to be our focus for today.

In today's article we will turn our attention to the fs module in NodeJS and as such we will consider the following;

- How to create a File
- How to read a file
- How to delete a file
- How to create a directory
- How to read a directory
- How to move a file
- How to delete a directory

## Creating a file

First you need to import the fs module.

```javascript
const fs = require('fs');
```

Next let's declare a function that will help create the file.

```javascript

const createFile = async (fileName) => {
  try {
    const file = fs.createWriteStream(fileName);
    return file;
  } catch (error) {
    console.log(error)
  }
}
```

We create a variable `createFile` which is equal to an async function, that accepts a single parameter `fileName` which will serve as the name of the file. Inside the function we use a `try/catch` block to wrap the process of creating a file. Inside the `try` block we call `fs.createWriteStream` and pass in the fileName as an argument to it. I store the result in a variable `file` and I'm just going to return the file. Inside the `catch` block we just `console.log` any error NodeJS encounters while trying to create that file for us. Let's consume this function.

```javascript
createFile(__dirname + '/index.json')
  .then(file => {
    file.write(JSON.stringify({ title: 'Mr.' }));
    console.log('file created successfully!');
  })
```

To consume the function we call `createFile` function and pass in `__dirname` + `/index.json` as the file name and this will create a file named index.json inside the current directory we are working inside. Next we use the write method on the file to add some JSON to the file. We run this file from the terminal using `node index.js` command and we get back the message file created successfully and upon inspecting the current working directory we see that the file has been created for us.

## Read File
```javascript

const readFile = (fileName, callback) => {
  try {
    const readStream = fs.createReadStream(fileName);
    let data = [];
    readStream.on('data', (chunk) => {
      data += chunk
    });
    readStream.on('end', () => {
      callback(null, data)
    })
  } catch (error) {
    callback(error, null);
  }
}
```

I have created a variable `readFile` which is equal to an arrow function, the function expects two parameters. The first is `fileName` is the name of the file and the second is `callback` a callback function. Inside the `readFile` function we add a `try/catch` block and in the catch block we call `callback` and pass in the error as the first argument to it and null as the second argument to it. Inside the try block I have created a variable `readStream` which is equal to calling `fs.createReadStream` I pass the `fileName` argument to it.

I create a second variable `data` which is equal to an empty array. This variable will store the contents of the file we read. I listen for the data event on the `readStream` and set the `data` variable to be += equal to the chunk of data we get from the `readStream`. Then I listen for the end event on the `readStream` and call the callback function we provided with null as the first argument and the data object we created earlier as the second argument. Let's consume the readFile function.

```javascript
readFile(
  __dirname + '/index.json',
  (error, data) => {
    if (error) console.log(error)
    if (data) console.log(data)
  }
)
```

To consume the `readFile` function we call it and pass in the path to the `index.json` file which we created earlier. The second argument we pass to the readFile function is a callback that accepts two argument, the first represents an error object while the second is the data that is read from the file. Inside the function we check if there's an error object and we log it out to the console, otherwise we just logout the data if it exits. Save the file and run it from the console and we get an object with title property.

## Delete a file

```javascript

const deleteFile = (file) => {
  fs.unlink(file, (err) => {
    if (err) throw err;
    console.log(`${file} was deleted`);
  })
}

```
I have created a variable `deleteFile` which is equal to an arrow function, this function accepts a single parameter `file` which represents the path to the file we want to delete. Inside the function we call `fs.unlink` and pass the file to it, the unlink function accepts two parameters, the first is the path to file we want to delete. The second argument we pass to the unlink function is an error handler function which will be called with an error object if NodeJS encounters any error while trying to delete the file, we just throw the error if there's one otherwise we just inform the user that the file has been deleted. Let's consume the function next.

```javascript
deleteFile(__dirname+'/index.json');
```

In order to delete the `index.json` file we created earlier we call the `deleteFile` function and pass in the path to the file. Save and run `node index.js` from the terminal and we see that the file has been deleted.

## Create a folder

```javascript
const createDirectory = (name) => {
  try {
    fs.mkdir(name, (err) => {
      if (err)
        throw Error(err.message);
    });
  } catch (error) {
    throw error
  }
}
```

Let's create a variable `createDirectory` which is equal to an arrow function. This function accepts a single parameter, `name` which will serve as the name of the folder we are trying to create. Inside the function we use the `try/catch` syntax to wrap the process of creating the folder. Inside the `catch` block we throw any error NodeJS encounters while trying to create the folder for us. Inside the `try` block we call `fs.mkdir` and pass in the name as the first argument to it, the `mkdir` function accepts two argument, the first is the name of the folder we want to create while the second is an error handler function that will be called with an error object. Inside the error handler function we just throw any error we encounter while trying to create the folder. Then we notify the user that the folder has been created. 

```javascript
createDirectory('helper');
```

To create our folder we call the `createDirectory` function and pass in `helper` as the name of the folder we want to create, save it and run it from the command line and you we see that the directory has been created for us.

## Read a directory

To read a directory you need to use the `fs.readdir` function, this function accepts two parameters, the first is the path to the directory we want to read and the second is a NodeJS style callback function that accepts an error object and a data object. Let's see how this function works.

```javascript
const fs = require('fs');
const {promisify} = require('util');
const readdir = promisify(fs.readdir);
const checkFiles = async (directory = __dirname) => {
  const files = await readdir(directory);
  console.log(files);
  return files.length;
}
```
We import and destructure the promisify function from the `util` library. The `util` library comes baked in with NodeJS by default. We call the promisify function and pass in `fs.readdir` as argument to it, I'm going to store the result in a variable readdir.

Let's create a variable `checkFiles` which is equal to an async function, the function accepts a single parameter `directory` which is an optional parameter, When we call the `checkFiles` function we don't always need to pass an argument to it and if we don't then the function will read the current directory we are working with. Inside the `checkFiles` function we create a variable `files` which is equal to the result of calling `await readdir` and passing in the `directory` to it then we return the files in the directory.

```javascript
checkFiles().then((contents) => {
  console.log(contents)
});
```

I call checkFiles and chain the `then` method to it, inside the `then` method we just console log the contents of the file, let me save the file and run it from the console, and you see we get an array of the files in the folder.

## Move file

To move a file in NodeJS you can use the rename function, and let's see how we can achieve this.

```javascript
const rename = promisify(fs.rename);

const moveFiles = async (
  newDirectory, 
  files
) => {
  try {
    files.forEach(async (file) => {
      await rename(file, `${newDirectory}/${file}`);
    });
    console.log('file moved');
  } catch (error) {
    throw error;
  }
}
```

I have converted the rename function on the fs module to a promise by calling the promisify function and saving the result in a variable rename. Next I'm going to create a variable `moveFiles` which is equal to an `async` function. The function accepts two parameters, the first is the new folder we want to push the file inside and the second is an array of files we want to move. 

Inside this function I use the `try/catch` block and inside the `catch` block i just throw any error encountered while trying to move the files. Inside the `try` block I call the forEach method on the `files` array and call the rename function for each file in it. The rename function expects two parameters, the first is the file we want to rename, the second is the new name for the file and in this this instance it is the path to the new folder and the name of the file. Then I'm going to alert the user that the file has been created by sending a message to the console.

```javascript
const files = [
  'my-image.jpg',
  'my-image.png'
];

moveFiles(`${__dirname}/helper`, files)
```

I've created an variable files which is equal to an array of files I'll like to move then I call `moveFiles` and pass in the `helper` directory we created earlier as the first argument to it then I pass in the array we created earlier as the second argument to it. Let me save this file and run it again from the console and you can observe that we get the message that the files have been moved.

## Delete a folder

To delete a folder you can use the fs.rm function, let's see how this function works.

```javascript
const emptyDir = async (directory,  {empty}) => {
  try {
    fs.rm(directory, { recursive: empty }, (err) => {
      if(err) throw Error(err);
    });
  } catch (error) {
    throw error
  }
}
```

I have created a file `emptyDir` which is equal to an async function. The function expects two parameters, the first is `directory` which is the path to the directory we want to delete and the second is an object with an empty property which is a boolean. Inside the function we use the `try/catch` syntax to handle this process. Inside catch block we throw any error encountered while trying to delete that directory while in the try block, I call `fs.rm` then I pass in the directory as the first argument to it, next I pass in an object with a property recursive which is a boolean that indicates wether or not NodeJS should empty the directory and it's equal to the empty variable we destructured from the config object while the last argument we pass to this function is an error handler function that will be called if any error is encountered while trying to delete the directory. Then we alert the user that the directory has been deleted by printing a message to the console.

```javascript
emptyDir(
  __dirname + '/helper',
  { empty: true }
)
```

I'm going to call the `emptyDir` function and pass in the path to the `helper` folder we created earlier, then I pass in an object with an empty property which is equal to true because I want to delete the folder and all it's content because I moved some file into it. Save the file and run it from the terminal and we get the message that the directory has been deleted!