Node.js File System Module

I. What is Node.js File system module?

In our computer, data is organized and accesed through a file system. The Node.js file system module allows us to interact with the file system.

fs handles file system operations such as reading to and writing from files. There are synchronous and asynchronous methods in the library.

To include the File System module, we can use the require() method:

const fs = require("fs");

Some of the methods include:

  • fs.readFile(): reads files asynchronously
  • fs.writeFile(): writes data to files asynchronously
  • fs.rename(): renames the specified file

II. Working with files in Node.js

1. Read file

To read the content of a file using NodeJS, we can use readFile() and readFileSync() methods

1.1 readFile()

The fs.readFile() method allows us to read the content of a file asynchronously, so the execution of JavaScript code will continue down the line without waiting for the method to finish.

It takes 3 parameters:

  • A relative path to the file we want to read
  • A character encoding
  • A callback function that will fire when this is completed
const fs = require("fs");

fs.readFile("./docs/blog.txt", "utf8", (err, data) => {
  if (err) throw err;
  console.log(data);
});

// Hello world

Note: If we don’t add utf8, when we run the file, it will return a buffer, which is a package of data.

To see our string data in text format, we can use toString() method:

const fs = require("fs");

fs.readFile("./docs/blog.txt", (err, data) => {
  if (err) throw err;
  console.log(data.toString());
});

// Result: Hello world

1.2 readFileSync()

The readFileSync() method reads the content of a file synchronously, so the JavaScript code execution will be stopped until the method is finished.

It has 2 parameters:

  • A relative path to the file we want to read (string type)
  • Options: The encoding format of the file content to read with (string or object type)
const fs = require("fs");

const data = fs.readFileSync("./docs/blog.txt", "utf8");

console.log(data);

2. Write file

To write file, we use fs.writeFile() method. It takes 3 arguments:

  • The first argument is a relative path to the file we want to write to
  • The second argument is a text we want to write to this file
  • The third argument is a callback function

For example, we’d like to replace “Hello world” with “Hello there”:

const fs = require("fs");

fs.writeFile("./docs/blog.txt", "Hello there", () => {
  console.log("file was changed");
});

// Result: file was changed

The fs.writeFile() asynchronously writes data to the file, replacing the file if it already exists. If the file does not exist, a new file will be created.

For example, if we run the following code, we’ll see blog2.txt appears in our folder.

const fs = require("fs");

fs.writeFile("./docs/blog2.txt", "Hello there", () => {
  console.log("file was changed");
});

// Result: file was changed

3. Append file

Because fs.writeFile() overwrite data, if we want to add more to a file, we need to use fs.appendFile().

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

// Create and write to file
fs.writeFile("./docs/blog.txt", "Hello World!", (err) => {
  if (err) throw err;
  console.log("Writing file ...");

  // File append
  fs.appendFile("./docs/blog.txt", "Learning Nodejs", (err) => {
    if (err) throw err;
    console.log("Appending file ...");
  });
});

4. Rename file

To rename a file, we use fs.rename(). It takes 2 arguments:

  • The first argument is a relative path to the file we want to rename
  • The second argument is a relative path with a new name
  • The third parameter is a callback function
// Rename file
fs.rename("./docs/blog.txt", "./docs/newblog.txt", (err) => {
  if (err) throw err;
  console.log("File renamed...");
});

5. Delete file

To delete a file, we use fs.unlink() method. It takes 2 arguments:

  • The first argument is a relative path to the file we want to delete
  • The second argument is a callback function
const fs = require("fs");

fs.unlink("./docs/blog2.txt", (err) => {
  if (err) {
    console.log(err);
  }
  console.log("file deleted");
});

// Result: file deleted

6. Check if a file exists

We can check whether a file or a directory exists or not before deleting it with fs.existsSync() method.

const fs = require("fs");

if (fs.existsSync("./docs/blog2.txt")) {
  fs.unlink("./docs/blog2.txt", (err) => {
    if (err) {
      console.log(err);
    }
    console.log("file deleted");
  });
}

III. Working with directories/ folders

1. Create a folder

To create a new folder, we can use fs.mkdir() method. We’ll need to specify what folder to make and where.

const fs = require("fs");

fs.mkdir("./images", (err) => {
  if (err) {
    console.log(err);
  }
  console.log("folder created");
});

2. Check if a folder exists

We can check whether a folder exists or not before creating it with fs.existsSync() method.

const fs = require("fs");

if (!fs.existsSync("./images")) {
  fs.mkdir("./images", (err) => {
    if (err) throw err;
    console.log("folder created");
  });
}

3. Remove a folder

const fs = require("fs");

fs.rmdir("./images", (err) => {
  if (err) {
    console.log(err);
  }
  console.log("folder deleted");
});

Resources: Check fs Documentation for more methods.

IV. Stream

If a file is large, it can take a long time to read so we’ll waste time waiting. To avoid that, we can use Streams.

Using stream, we can start using the data before it has finished loading.

1. Read stream

To open a file as a readable stream, we can use fs.createReadStream(). It takes 2 arguments:

  • The first argument is the path of where we want to read and pass data from
  • The second argument is an object { encoding: "utf8" } so the stream will be in a readable format.

We’ll then create an event listener to whenever we create a chunk of data:

const fs = require("fs");

const readStream = fs.createReadStream("./docs/blog3.txt", {
  encoding: "utf8",
});

readStream.on("data", (chunk) => {
  console.log("--New Chunk--");
  console.log(chunk);
});

2. Write stream

We can use fs.createReadStream() to write data to a file a bit at a time.

For example, we’ll pass data of blog3 to blog4:

const fs = require("fs");

const readStream = fs.createReadStream("./docs/blog3.txt", {
  encoding: "utf8",
});
const writeStream = fs.createWriteStream("./docs/blog4.txt");

readStream.on("data", (chunk) => {
  writeStream.write(chunk);
});

V. Pipe

Using pipe, we can pass data from a readable to a writable stream in a much shorter way

const fs = require("fs");

const readStream = fs.createReadStream("./docs/blog3.txt", {
  encoding: "utf8",
});
const writeStream = fs.createWriteStream("./docs/blog4.txt");

readStream.pipe(writeStream);