Being able to read and write from files on the local file system can be very useful for logging, exporting and importing data from JSON and XML files, transferring data from one place to another place, and much more.

Like any other programming language, Node.js provides native fs module for manipulating operating system files. Using this module, you can easily read, write, and watch files along with many other things.

In this tutorial, we will learn how to read and write files from our local files system using Node.js FS package.

No installation required. Since fs is native module, you do not need to install it. Just import it in your code by calling const fs = require('fs').

The fs module gives us both asynchronous and synchronous options to handle files:

  • Synchronous option blocks the execution of the code until the file operation is completed.
  • Asynchronous option does not block the execution of code. Once the file operation is completed, it invokes a callback function.

Reading From Files

The simplest way to read a file in Node.js is to use fs.readFile() method that asynchronously reads the entire contents of the file. It takes two arguments: the file path and a callback function that will be called with the file data:

const fs = require('fs');

fs.readFile('file.txt', (err, data) => {
    if(err) {
        throw err;
    }
    console.log(data.toString());
});

The callback function is passed two arguments: err & data, where data is the contents of the file. The err object contains the information about runtime errors (if any).

Another way of reading a file is using the synchronous version of fs.readFile() called fs.readFileSync():

const fs = require('fs');

try {
    const data = fs.readFileSync('file.txt');
    console.log(data.toString());
} catch (err) {
    console.error(err);
}

The default file encoding is UTF-8. If no encoding is specified, then the raw buffer is returned. So if you don't want to see the buffer being printed out in the terminal, specify the file encoding as the second parameter after the file path:

const fs = require('fs');

fs.readFile('file.txt', 'utf-8', (err, data) => {
    if(err) {
        throw err;
    }
    console.log(data);
});

Both fs.readFile() and fs.writeFile() functions read the full contents of the file in memory before calling the callback function. So if you are reading a large file, it might have an impact on your memory consumption and execution of the program.

For large files, it is better to use streams for reading contents of a file.

Writing To Files

The easiest way to write data to files in Node.js is by using the fs.writeFile() method from the same fs module. It takes three arguments — the file name, the data to write, and a callback function — and writes the data asynchronously:

const fs = require('fs');

const data = "This is the new content of the file.";

fs.writeFile('file.txt', data, (err) => {
    if(err) {
        throw err;
    }
    console.log("Data has been written to file successfully.");
});

Creating New File: The above example will automatically create a new file for you if it does not exist. It is particularly helpful for creating a new file and then writing to it in one go.

The fs.writeFileSync() is another version of this method for writing to files synchronously:

const fs = require('fs');

const data = "This is the new content of the file.";

try {
    fs.writeFileSync('file.txt', data);
    console.log("File has been saved.");
} catch (error) {
    console.error(err);
}

By default, these methods override the contents of the file if it already exists. If you want to append data to the file, you should pass a flag as the 3rd parameter:

const fs = require('fs');

const data = "Append this data at the end of the file.";

fs.writeFile('file.txt', data, {flag: 'a+'}, (err) => {
    if (err) {
        throw err;
    }
    console.log("FIle is updated.");
});

Some of the flag options you are most likely to use:

  • r — Open the file in read-only mode. An exception is thrown if file does not exist.
  • r+ — Open the file for reading and writing. If the file does not exist, an exception is thrown.
  • w — Open the file in write-only mode. The file is created (if does not exist) or truncated (if exists).
  • w+ — Open the file for reading and writing, placing the stream at the start of the file. The file is created if doesn't exist.
  • a — Open the file for appending, positioning the stream at the end of the file. The file is created if doesn't exist.
  • a+ — Open the file for reading and appending, putting the stream at the end of the file. The file is created in case if it does not exist.

Both these methods continue writing to the file until the full contents have been written, before returning the control back to your program. If you are writing a lot of data, it might impact your application performance.

In this case, a better approach would be to use stream for writing to large files.

Appending To Files

Besides using flags for appending data at the end of the file, the fs module also provides fs.appendFIle() (and fs.appendFIleSync() for synchronous) method that asynchronously append data to the file, creating the file if it does not yet exist:

const fs = require('fs');

const data = "Some data to append";

fs.appendFile('file.txt', data, (err) => {
    if (err) {
        throw err;
    }
    console.log("FIle is updated.");
});

Error Handling

If there is a runtime error while reading or writing to a file, the callback method is called with an Error object as the first argument.

The simplest way to handle runtime errors is to throw them as Node.js exceptions as we used above. But this will crash the application, and is therefore not recommended except in cases where you don't have any other option:

const fs = require('fs');

fs.readFile('404.txt', 'utf-8', (err, data) => {
    if (err) {
        console.error(err);
        // log the error here
    }
    console.log(data);
});

Now if you execute the above code, you would see something like the following printed on the terminal:

{ [Error: ENOENT: no such file or directory, open '404.txt'] 
	errno: -2, 
	code: 'ENOENT', 
	syscall: 'open', 
	path: '404.txt' }
undefined

Conclusion

That's all folks for reading and writing files using Node.js native fs module. I hope you found this tutorial useful. If you have any questions or comments, you can always reach out to me on Twitter.

Further Reading

If you enjoyed reading this article, you may also like some of my other articles:

Until next time, Bye!

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Buy me a coffee (cost $3)

Need help to start a new Spring Boot or MEAN stack project? I am available for contract work. Hire me to accomplish your business goals with engineering and design. Let’s talk about your project: hi@attacomsian.com.