Get the Total Size of All Files in a Directory Using Node.js
How do you get the total size of all the files in a directory and any sub-directories using Node.js?
You can do this by using both the Fs core module and some custom code to recursively go through each directory (and sub-directories) to retrieve each individual file. Once you have each file, you can easily get the sum of each of their file sizes.
In this article, we'll walk you through each of the three steps to do this:
- Get all the files in the directory by recursively going through all the sub-directories and returning an array of file paths (the
fs
module will be utilized for this step). - Loop through each file in the array of file paths and generate a sum of all their individual file sizes.
- Create a function that transforms the bytes result from the previous step into a human-readable value in KB, MB, GB, or TB units.
For the full code solution, you can jump to the end of the article.
To follow along with the code in this article, you'll need to have Node.js installed on your local development machine.
If you need one, we wrote a guide on how to get Node.js installed on your machine.
Let's get started!
Table of Contents
- Get All the Files in the Directory
- Add Up the Combined Byte Size of Each File
- Convert Bytes to Human-Readable Format
Step 1 - Get All the Files in the Directory
The first thing we need to do is get all the files in the directory. And this includes recursively going through to get any files in sub-directories.
To do this, we'll create a function that takes a directory path as a parameter and returns an array of file paths as a result.
If the function encounters any sub-directories, it will recursively call itself. It will do this as many times as necessary until no more sub-directories are encountered.
Here's what the code looks like:
const fs = require("fs")
const path = require("path")
const getAllFiles = function(dirPath, arrayOfFiles) {
files = fs.readdirSync(dirPath)
arrayOfFiles = arrayOfFiles || []
files.forEach(function(file) {
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles)
} else {
arrayOfFiles.push(path.join(__dirname, dirPath, file))
}
})
return arrayOfFiles
}
Let's go over each part of the code.
The getAllFiles
variable holds the recursive function that will go through each subdirectory and return an array of filenames. It takes a directory file path and an optional arrayOfFiles
as arguments.
Inside the getAllFiles
function, we first use the readdirSync()
function to get all of the files and directories inside the given dirPath
supplied to the function.
Then, we create an arrayOfFiles
that will hold all the filenames that will be returned when the function is done running.
Next, we loop over each item (file or directory) found by the readdirSync()
function. If the item is a directory, we have the function recursively call itself to get all of the files and sub-directories inside the given directory.
And if the item is a file, we simply append the filename to the arrayOfFiles
array.
When the forEach
loop has finished, we return the arrayOfFiles
array which contains all the files in the directory.
This function can be used like this and will return an array of file path strings:
const result = getAllFiles("PATH_TO_PARENT_DIRECTORY")
// [ "FILE_PATH", "FILE_PATH", "FILE_PATH" ]
To avoid that, you can replace the fs.readdirSync()
method in the function with it's fs.readdir()
synchronous counterpart.
Now that we know how to get all the files in the directory, we can add the file size of each one together in the next step.
Step 2 - Add Up the Combined Byte Size of Each File
Now, let's create a function that takes a directory path, runs the getAllFiles
function we created early, and loops through each item in that array and adds together each file size value.
Add this function in the same file as you used in the last example:
const fs = require("fs")
const getTotalSize = function(directoryPath) {
const arrayOfFiles = getAllFiles(directoryPath)
let totalSize = 0
arrayOfFiles.forEach(function(filePath) {
totalSize += fs.statSync(filePath).size
})
return totalSize
}
We name our function getTotalSize
and configure it to take a directory path as its sole parameter.
Inside the function, the first thing we do is get the array of file paths using the getAllFiles
function we created in the last section.
Then, we use the forEach()
method to loop over each item in the array and increment the totalSize
value by the file size of each item in the array (in bytes).
When the loop is complete, the totalSize
value is returned. That value will be a large number in the bytes format.
You can call the function like this:
const result = getTotalSize("./directory-name")
// 163753
The integer returned is a bytes value because the fs
module only reads file sizes in those unit types. Therefore, the returned number doesn't mean much to humans.
In the next function, we'll build a quick function that formats that bytes value nicely and makes it human-readable.
Step 3 - Convert Bytes to Human-Readable Format
At this point, we have a bytes value that represents the total combined size of every file in the directory. But, what's the point of all that work we did in the previous sections if no one can understand the data we retrieved.
In this section, we'll build a function that takes a bytes value as a parameter and converts it into a formatted and human-readable KB, MB, GB, or TB version.
Here's the code:
const convertBytes = function(bytes) {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"]
if (bytes == 0) {
return "n/a"
}
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
if (i == 0) {
return bytes + " " + sizes[i]
}
return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i]
}
Before going through the code, it's worth noting that we use 1024
as the base unit for all conversions. We use that number because a kilobyte represents 1024 bytes in the binary system. And a megabyte is 1024 kilobytes and so on.
The first thing we do is create a function named convertBytes()
that takes a bytes
integer as its sole argument.
Inside the function, we create a sizes
array of strings. This will store each of the potential labels (Bytes, Kilobyte, Megabyte, Gigabyte, Terabyte) that we'll use when creating a new string value representing our original bytes
parameter value. Each of these will be accessed by their index value later on in the function.
Then, we create an if statement that returns the string "n/a"
if the bytes
parameter value is equal to zero.
Next, we need to figure out what file type we need to use from the sizes
array. The variable named i
will represent the index of that string in the sizes
array. That value is determined by dividing the log of bytes
value by the log of 1024
(file sizes are based on those units).
If the i
index value is equal to 0
, we'll return a string with the "bytes"
label on it.
Otherwise, we'll return a string with the formatted bytes
value to one decimal point. And the file type from the sizes
array will be added to the end of the string as well.
Here are some examples of the function in practice:
convertBytes(0) // "n/a"
convertBytes(500) // "500 Bytes"
convertBytes(2000) // "1.0 KB"
convertBytes(2024000) // "1.9 MB"
convertBytes(2550024000) // "2.4 GB"
convertBytes(1292550024000) // "1.2 TB"
As you can see, the function works as expected in providing a given bytes
integer into a human-readable format.
Make sure you add the convertBytes
function to the same file as the other functions and you can use it when you return the final totalSize
value:
return convertBytes(totalSize)
When you run the function, you'll notice that the final value is no longer in bytes, but a nicely formatted and human-readable format instead.
In this article, we've covered how to get the total size of all files in a given directory. We've done it by first getting an array of all the files in the directory and its sub-directories, then we added all of the file sizes together, and formatted the bytes into something human-readable.
For your reference, here's the full code:
const fs = require("fs")
const path = require("path")
const getAllFiles = function(dirPath, arrayOfFiles) {
files = fs.readdirSync(dirPath)
arrayOfFiles = arrayOfFiles || []
files.forEach(function(file) {
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles)
} else {
arrayOfFiles.push(path.join(__dirname, dirPath, file))
}
})
return arrayOfFiles
}
const convertBytes = function(bytes) {
const sizes = ["Bytes", "KB", "MB", "GB", "TB"]
if (bytes == 0) {
return "n/a"
}
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
if (i == 0) {
return bytes + " " + sizes[i]
}
return (bytes / Math.pow(1024, i)).toFixed(1) + " " + sizes[i]
}
const getTotalSize = function(directoryPath) {
const arrayOfFiles = getAllFiles(directoryPath)
let totalSize = 0
arrayOfFiles.forEach(function(filePath) {
totalSize += fs.statSync(filePath).size
})
return convertBytes(totalSize)
}
const result = getTotalSize("./my-directory")
// 159.9 KB
If you don't want to deal with creating this custom code, there is a NPM package named get-folder-size that will handle this functionality for you. Hopefully, this was helpful in your coding endeavors.