Node.js File System & Setting up File Structure

    0 Votes

In our previous tutorials we have written application to read contents of a file, colorize it and display it to the use. But where would we actually need this apart from showing Hello World Application? Files can be used to store data, configuration or templates. In this article we will see various functions related to file systems in NodeJS.

Clearing up a misconception:

Many people think that NodeJS is just a runtime environment for running JavaScript code as a server. BUT NodeJS is much more than this. NodeJS is a runtime environment. This means that you can create standalone tools which can run in your systems

These stand alone tools would sometime require extensive use of file system like if you write a Command Line Interface (CLI) to manage files (i.e. a better replacement for ‘cd’, ‘ls’, ‘mkdir’, etc...).

More than Hello World Application

Reading a file

First let’s create a new Project with the following folder structure:

folder structure nodejs

With the contents as:

index.js

"use strict"; 
const fs = require('fs'); 
const path = require('path'); 
let readFileSyncFunction = function(argument)
{
	console.log("Starting sync read");
	let str = fs.readFileSync(path.join(__dirname,"myFolder","myTextFile.txt")).toString();
	console.log("Contents sync : " + str);
}
let readFileAsyncFunction = function(argument)
{
	console.log("Starting Async read");
	fs.readFile(path.join(__dirname,"myFolder","myTextFile.txt"), function(err, buf)
	{
	 console.log("Contents Async : " + buf.toString());
	});
	console.log("End of async read");
}

readFileSyncFunction();
console.log("\n\n.........\n\n");
readFileAsyncFunction();

myFolder/myTextFile.txt



text file

text file read

We have already discussed these functions in earlier tutorials. The output as expected will be:

For the further examples, we will work with synchronous functions but asynchronous will also work as charm and should be preferred in real applications.

"use strict"; 
const fs = require('fs'); 
const path = require('path'); 
let readFileSyncFunction = function(argument)
{
	let str = fs.readFileSync(path.join(__dirname,"myFolder","myTextFile.txt")).toString();
}
readFileSyncFunction();

Clear up the index.js to remove asynchronous function

Checking Existence of Files and Folders

Let's say we delete the myTextFile.txt from the folder, what would happen?

file exists

You would get an error and the script with crash. See the error (highlighted):

As you might have guessed, it is because the text file does not exists. So we need a check to read the file only if the file exists.

Change the readFileSyncFunction() as :

let readFileSyncFunction = function(argument)
{
	let filePath = fs.readFileSync(path.join(__dirname,"myFolder","myTextFile.txt"));
	if(fs.existsSync(filePath))
	{
		let str = fs.readFileSync(filePath).toString();
	}
	else
	{
		console.log("File does not exists");
	}
}

Here we create a variable filePath which will store the path of file we need. We use this variable as we would frequently use the file path and we should reduce function calls.

In line 8, we check if the file exists using a function in fs module, fs.existsSync(filePath) . This function returns true if the file exists else returns false. So if the file exists, we display the string else show an error. See the output.

exists sync file

We can also check for existence of folder using the fs.existsSync() function and it is a good practice to do so. See the code below.

let folderPath = path.join(__dirname,"myFolder");
let filePath = path.join(folderPath,"myTextFile.txt");
if(fs.existsSync(folderPath) fs.existsSync(filePath))
{
	let str = fs.readFileSync(filePath).toString();
	console.log(str);
}
else
{
	console.log("File does not exists");
}

Retrieving information about a file or folder

Now let's say we need information of a file on the disk. The fs module provides a function statSync() to extract information from a file. See the example below

let readFileSyncFunction = function(argument)
{
	let folderPath = path.join(__dirname,"myFolder");
	let filePath = path.join(folderPath,"myTextFile.txt");
	if(fs.existsSync(folderPath) fs.existsSync(filePath))
	{
		let fileStats = fs.statSync(filePath);
		console.log(fileStats);
	}
	else
	{
		console.log("File does not exists");
	}
}

The fs.statSync(filePath) function returns some information about the file. See output below. We can make out some information from here but most of this is garbage for us.

retrieve file info details

The object returned by the fs.statSync() function (here fileStats) provides various functions which can be used. Two such functions are

  • isDirectory()
  • isFile()

These functions are used to determine if the path provided is a file or a directory.

let folderStats = fs.statSync(folderPath);
console.log(folderStats);
console.log("Is " + filePath + " a directory?"+ fileStats.isDirectory());
console.log("Is " + folderPath + " a directory?"+ folderStats.isDirectory());

console.log("Is " + filePath + " a file?"+ fileStats.isFile());
console.log("Is " + folderPath + " a file?"+ folderStats.isFile());

So now we can figure out if the file exists, the contents of a file, information of file etc. Let's see more interesting things.

Writing to a file

"use strict"; 
const fs = require('fs'); 
const path = require('path'); 
let writeToFile = function()
{
	let content = process.argv[2];
	let str = path.join(__dirname,"myFolder","myTextFile.txt");
	fs.writeFileSync(filePath, content);
	console.log("Finished writing to file");
};
writeToFile();

Clear the index.js file and write the following code in it

First we declare a function writeToFile() which will do our required operation.

In this function, first we set the content to process.argv[2]. process.argv is a global variable which store the command line arguments. When running in terminal,

  • process.argv[0] equals “node”
  • process.argv[1] equals “index.js”
  • and so on.

The we write the content to the file using fs.writeFileSync() which accepts to arguments – file path and content of file to be written. This will overwrite the contents of the file. If the file does not exists, then it is created. It will not create directories if they don't exists. Lets see the output

write to file output

On running this script, you would have got a new file “myNewFile.txt” in the “myFolder” directory with the contents:

Deleting a file

An existing file can be deleted by using fs module. The module provides a function fs.unlinkSync() to achieve this functionality. Let’s see an example.

let removeTextFile = function()
{
	let folderPath = path.join(__dirname,"myFolder");
	let filePath = path.join(folderPath,"myTextFile.txt");
	if(fs.existsSync(folderPath) ) &&  fs.existsSync(filePath))
	{
		fs.unlinkSync(filePath);
		console.log("filepath " + removed);
	}
	else
	{
		console.log("File does not exists");
	}
};
removeTextFile();

Creating a directory

NodeJS can be used to create a new directory in the disk using the fs module. The fs module exposes a function fs.mkdirSync() which accepts a parameter – directory path. For creating a directory, its parent directory should exists. i.e if you want to create a directory myFolder/mySubFolder/newFolder , then you should ensure that mySubFolder exists in myFolder directory else it will crash.

let createNewFolder = function()
{
	let folderPath = path.join(__dirname,"myFolder");
	if(fs.existsSync(folderPath))
	{
		fs.mkdirSync( path.join(folderPath,"mySubFolder"));
		console.log("Created a new sub directory ");
	}
};
createNewFolder();

Reading contents of directory

The fs module provides a function fs.readdirSync() which accepts a parameter – directory path, and returns an array of strings which are the file/directory names (along with extensions for files) contained in the directory. You need to use fs.statSync() function to check again if a particular name represents a file or a directory.

let readDir = function()
{
	let folderPath = path.join(__dirname,"myFolder");
	if(fs.existsSync(folderPath))
	{
		let contents = fs.readdirSync(folderPath);
		console.log(contents);
	}
};
readDir();

Deleting a directory

The fs module exposes a functions fs.rmdirSync() which accepts path of the directory to be removed as its argument. Note: This command can only delete empty directories. If the directory is not empty then you need to remove its contents using fs.unlinkSync() or fs.rmdirSync() on child directories.

let removeDir = function()
{
	let folderPath = path.join(__dirname,"myFolder");
	if(fs.existsSync(folderPath))
	{
		fs.readdirSync(folderPath).forEach(function(content)
		{
			let stat = fs.statSync(path.join(folderPath, content));
			if(stat.isDirectory())
			{
				removeDir(content, folderPath);
			}
			else
			{
				fs.unlinkSync(path.join(folderPath, content));
			}
		});
		fs.rmdirSync(folderPath);
	}
};
removeDir("myFolder", __dirname);

A quick note:

All the functions mentioned in the fs module contain both the synchronous as well as asynchronous methods.

Synchronous methods: fs.<method_name>Sync(arguments...)

Asynchronous methods: fs.<method_name>(arguments..., callback)

i.e. A synchronous function name ends with “Sync” while an asynchronous function does not contain “Sync” in its name. Also the async functions have an extra arguments – the callback function to be executed after the operation is one asynchronously. The callback will always have the first argument as error.

Popular Videos

communication

How to improve your Interview, Salary Negotiation, Communication & Presentation Skills.

Got a tip or Question?
Let us know

Related Articles

Node.js Introduction & Environment Setup
Node Package Manager (NPM)
Global Variables in Node.js
Node.js Callbacks
Event Loop & Event Emitters in Node.js
Node.js Buffers and Streams