Creating, Amending and Deleting files using NodeJS

·

7 min read

An introduction to Node.js

Node.js is a free open source environment which uses JavaScript to write server side code.

It can create, open, read, write, delete and close files on the server. In concise words, to manage the working of server Node.js is a very common and useful tool.

Node.js files have .js as extension type since the code are written in JavaScript.

The console will be in the terminal window not in the browser window unlike in our front end projects.

Important parts of Node.js

Buffer

Modules

Debugger

Console

Cluster

Add-ons

Callback

Crypto

Error Handling

Net

Global

Domain

DNS

Streaming

Node.js based server never stops the code execution while waiting for API to return data. The server moves to the next API after askin gfor data from an API. There is a notification mechanism of Node.js which tells regarding the response from API and due to this reason which makes the servers based on Node.js very fast.

Node.js is a single threaded model with event looping.

Check the version of npm and node.js

node --version -> Checks the version of Node installed on your local computer

npm -v -> Checks the version of npm

These two commands will give results only after Node.js has been correctly installed on your system.

Using the console in Node js

Go to the terminal and write node and press Enter . You will be able to open the console for Node now.

To exit the terminal you need to press Ctrl + C twice.

How to find the relevant documentation in NodeJS?

Go to their documentation. Press Ctrl + F and search the term you are looking for.

Consider you want to look for read file structure. Go to file structure and search for read

Callback API

Callback API performs all operations asynchronously without blocking the event loop, then invoke a callback function upon completion or error.

All the below examples of write, read and ament will be a part of Callback section of NodeJS documentation.

Running your first Node program

const fs = require('fs');

fs.readFile('./lorem.txt', (err, data) => {
    if(err)console.log(err);

    else console.log(data.toString())

})

fs stands for sile system. lorem.txt is a file situated in the same folder as server.js data will be sent in form of packets. To read the data as it is .toString() method is used.

Press enter after typing 'node server' in terminal where server.js is a file saved on local directory

Instead of using .toString() you can also use 'utf8' as an argument.

const fs = require('fs');

fs.readFile('./lorem.txt','utf8', (err, data) => {
    if(err)console.log(err);

    else console.log(data)

})

Another way of specifying the path

Sometimes hardcoding path can give some error. Instead import path module and then use path.join()

The update code will look like this :


const fs = require('fs');
const path = require('path');


fs.readFile(path.join(__dirname, '.', 'starter.txt'),'utf8', (err, data) => {
    if(err)throw err;

    else console.log(data)

})

___directory is always available to use without any imports in Node

writeFile

As the name suggests, it is used to write the file. The syntax is a little different than readFile

You have to mention the path, 'Content to be written in file', Callback in the argument of writeFile.

The code goes like this


fs.writeFile(path.join(__dirname, '.', 'reply.txt'),'Heyy I replied', (err) => {
    if(err)throw err;

    else console.log('Write completed')

})

appendFile

writeFile will erase the old content and replace it entirely with new one that we provided. To make sure our previous data is not erased when we enter the new data appendFile is used which takes the similar arguments like writeFile.

The sample code is like this :


fs.appendFile(path.join(__dirname, '.', 'reply.txt'),'Heyy I replied again', (err) => {
    if(err)throw err;

    else console.log('Write completed')

})

`

If you put a name of the file that doesnot exist, append file will create a new file as well. Since NodeJS has asynchronous nature it is always better to put appendFile inside writeFile so that we don't create a file with appendFile and writeFile will overwrite it completely.

Here is how we do it.


fs.writeFile(path.join(__dirname, '.', 'replyNew.txt'),'Heyy I replied', (err) => {
    if(err)throw err;

    else console.log('Write completed')


    fs.appendFile(path.join(__dirname, '.', 'replyNew.txt'),' Heyy I replied again', (err) => {
        if(err)throw err;

        else console.log('Write completed for append')

    })

})

If we want to change anything of the file, it should be inside the amend block. For example, we have to change the name of the file after create writing something to it.

We have to use the rename function inside the amend block.

If you have a file named reply previously, it will be replaced with the new reply file.

This is how the code bloc kwill go with writeFile, amendFile and rename


fs.writeFile(path.join(__dirname, '.', 'replyNew.txt'),'Heyy I replied', (err) => {
    if(err)throw err;

    else console.log('Write completed')


    fs.appendFile(path.join(__dirname, '.', 'replyNew.txt'),'\n\nHeyy I replied again hero', (err) => {
        if(err)throw err;

        else console.log('Write completed for append')

        fs.rename(path.join(__dirname, '.', 'replyNew.txt'), path.join(__dirname, '.', 'reply.txt') , (err) => {
            if(err)throw err;

            else console.log('Rename completed for replyNew')

        })

    })

})

We are controlling the flow but we are also writing one code block inside another code block and so on. This seems to like we are in Callback hell and in JavaScript we avoid it using async/await and in NodeJS we will do the same.

The way to write an async function remains same. Following code contains a list of example of above operations but using asyc/await way.

const  fsPromises = require('node:fs/promises');
const path = require('node:path');

const fileOps = async () => {
  try{
      const data = await fsPromises.readFile(path.join(__dirname, '.', 'starter.txt'), 'utf8');
      console.log(data);
      fsPromises.unlink(path.join(__dirname, '.', 'starter.txt'));
      fsPromises.writeFile(path.join(__dirname, '.', 'promise.txt'), "Overwrote the text ")

      fsPromises.appendFile(path.join(__dirname, '.', 'promise.txt'), "\n\n Appended the text ")

      fsPromises.rename(path.join(__dirname, '.', 'promise.txt'), path.join(__dirname, '.', 'promiseUpdated.txt'))

      const newData = await fsPromises.readFile(path.join(__dirname, '.', 'promiseUpdated.txt'), 'utf8');
      console.log(newData);

  }catch(err){
    console.error(err);
  }
}

fileOps();

unLink deletes the file path specified and you will notice we don't need a callback function when we are using fsPromises.

The code becomes much cleaner than earlier.

Dealing with large amount of data

When we have a lot of data, it is not advised to grab all the data at once instead we should process the data in small chunks.

A similar analogy can be made when we have to do a bigger task like breaking a mountain, we break it in step by step in small portions.


const fs = require('fs');

const rs = fs.createReadStream('./lorem.txt', {encoding: 'utf8'});

const ws = fs.createWriteStream('./new-lorem.txt');

//listen to data coming from the stream usinf rs.on()
rs.on('data', (dataChunk) => {
    ws.write(dataChunk)
})

In the above code we first read data from the lorem.txt which is a very large file in our folder.

Once we create rs, we created a new file new-lorem using createWriteStream.

rs.on() is listening to the data we got from the createReadStream and inside it we gave a callback function which will write the content of lorem to new-lorem.

Instead of listening to the data we can use the pipe to do the same thing It will go as

rs.pipe(ws)

pipe is more efficient. As you can see, rs contents were copied to ws using pipe() method.

Create a new directory

mkdir is a well known command which stands for make directory. Using NodeJS we can create a directory too.

This is how we do it in NodeJS:

const fs = require('fs');

fs.mkdir('./new', err => {
    if(err) throw err;

    console.log('Directory created');
})

Node allows us to check whether a file is present or a directory is present or not. This prevents the creation of a new directory if it already exists and we do it using an if statement.

We use it when we want to unLink a file or rename a file. We must check if a file exists or not before doing operation on it.

In simple terms

If directory exists don't create it

We just have to tell this to the Node using existsSync method

if(!fs.existsSync('./new')){
    fs.mkdir('./new', err => {
        if(err) throw err;

        console.log('Directory created');
    })
}

Deleting a directory

Just like mkdir makes a directory, rmdir will remove the directory.

Don't forget to put a check to make sure the directory exists before deleting it.


if(fs.existsSync('./new')){
    fs.rmdir('./new', err => {
        if(err) throw err;

        console.log('Directory deleted');
    })
}

These concepts are enough to get us started with doing the file operations using Node. To polish the skills we must use the documentation provided by Node .

Thanks to Dave Gray