File System
Learn to use the file system module in Node.js.
We'll cover the following
The fs module
fs
is a built-in Node.js module that allows us to interact with the file system. It has quite a few methods, some of which have both synchronous and asynchronous variants. Before we move ahead with code examples, it should be noted that the asynchronous forms of the methods always take a completion callback as the last argument. For this callback, the first argument is reserved for an exception. This will be easier to understand once we see the code.
Reading files
The fs
module provides an easy way to read files using the fs.readFile
method. It is passed a file path, optional arguments, such as encoding, and a callback function that will be called with data read from the file. Let’s look at both the asynchronous and synchronous versions of this method.
const fs = require('fs')fs.readFile('test.txt', 'utf-8', (err, data) => {if (err) {console.error(err)return}console.log(data)})console.log("Hello!")
We need to import the fs
module in order to use the readfile
method. Both codes read from the test.txt file. This is the first argument passed to both methods. The second argument we passed is the encoding, utf-8
in our case. This ensures that the file is read in the same way it was stored.
- The
readFile
method is asynchronous and, hence, takes a completion callback as its last argument. This callback takes anerr
as an exception. If no exception occurs, this will be eithernull
orundefined
. The second argument of this callback isdata
. This represents the data that is read from the file. Since this is asynchronous, the process does not block and we see our Hello! before the file data. - The
readFileSync
method,as the name suggests, is synchronous. We have placed this in atry catch
block, as it is good coding practice and shall keep the process from terminating in case we are unable to read the file. Unlike the asynchronous method, this blocks the program until the file is read. This is why we see the file data first, followed by the Hello! in our output.
Both of these methods read the entire file into memory before they return. For very large files, this may impact our system memory consumption.
Try changing the arguments passed to both code examples to see how the output might change.
Writing to files
We can write to files in a similar manner as reading them. The aptly named writeFile
and the writeFileSync
methods can be used for this job. Let’s look at the code below.
const fs = require('fs')let content = "This is what will be written to the file"fs.writeFile('test.txt', content, (err) => {if (err) {console.error(err)return}console.log("File written!")})fs.readFile('test.txt', 'utf-8', (err, data) => {if (err) {console.error(err)return}console.log(data)})
We are writing to the file named test.txt. To check that the file was indeed written to, we read it again and output its content. What if we want to overwrite a file, or perhaps, create a file if it does not exist before writing to it? For these, we have flags
. flags
are optional parameters passed to different methods of the fs
module. These allow us to dictate how we would like to interact with the file. Check out all of the flags available here.
File stats
Sometimes, we need to do more than just read or write to a file. The fs
module has a stat
method that provides us with a lot of useful information about files. Let’s see how it works.
const fs = require('fs')fs.stat('test.txt', (err, stats) => {if (err) {console.error(err)return}console.log(stats)})
File descriptors
Node.js also provides a way to use file descriptors. If you are not familiar with file descriptors, you can simply think of them as a number that the OS uses to keep track of an open file. However, the readFile
and writeFile
methods discussed earlier provide an easier method to read and write to files. Let’s see how we can use file descriptors in Node.js.
const fs = require("fs");var fileName = "test.txt";fs.stat(fileName, (err, stats) => {if (err) {console.error(err);return;}fs.open(fileName, "r", (err, fd) => {var buffer = Buffer.alloc(stats.size);fs.read(fd, buffer, 0, buffer.length, null, (err, bytesRead, buffer) => {var data = buffer.toString("utf8", 0, buffer.length);console.log(data);fs.close(fd, (err) => {if (err) {console.error(err);return;}});});});});
-
We use the
stat
method to get thesize
of the file being read. Thissize
is used to create the buffer. -
The
open
method returns the file descriptor for the file at the path we passed as an argument. The argumentr
is the file system flag. These flags allow us to access files in different ways. You can read up on all the flags here. -
The
read
function on line 13 takes quite a few arguments. The first one being the file descriptor. The next 4 are options:buffer
is the Buffer that will be written to once the file descriptor is read. This is thebuffer
we created on line 11 in our case.offset
is the offset after which the buffer will be written to. Incase our buffer was not empty, we can specify this offset to begin writing after the previous content. This is0
in our case.length
corresponds to the number of bytes to be read. Since we want to read the entire file, we have set this tobuffer.length
.position
refers to where to begin reading the file. Setting it tonull
begins reading from the current file position.
Finally, a callback function is passed. This function returns an
error
,bytesRead
andbuffer
. ThebytesRead
is the number of bytes read into thebuffer
. -
We use the
close
method to close the file descriptor.
The fs
module is a very versatile and easy-to-use module that makes file handling possible with Node.js.
Get hands-on with 1300+ tech skills courses.