Bootstrap FreeKB - Node.js - List files in a directory using fs.readdirSync
Node.js - List files in a directory using fs.readdirSync

Updated:   |  Node.js articles

There are two similar but distinct modules that can be used to list files and directories in Node.js.

fs.readdirSync can be used to list the files and directories in a directory. In this example, the files and directories in the /tmp directory will be stored in a list named "files_and_directories" 

const fs = require("fs")

const base_directory = '/tmp'
const files_and_directories = fs.readdirSync(base_directory)

console.log(files_and_directories)

 

Be aware that if you are using a Node.js module instead of CommonJS, you will have "type": "module" in package.json. In this scenario, you will use import instead of require.

import fs from "fs"

 

Something like this should be returned.

[
  '.hidden_file',
  '.hidden_directory',
  'my_directory',
  'my.json',
  'foo.txt',
  'bar.txt'
]

 

fs.readdir is asynchronous where fs.readdirSync is not asynchronous. For example, let's say the /tmp/foo directory contains thousands of files and sub-directories and /tmp/bar only contains a few files. With fs.readdirSync (not asynchronous) the first block that gets all of the files and subdirectories in /tmp/foo must complete before moving onto the next block and gets the files in the /tmp/bar directory.

import fs from "fs"

fs.readdir('/tmp/foo', (err, files_and_directories) => {
  if (err) {
    console.error(err)
  } else {
    console.log(files_and_directories)
  }
})

fs.readdir('/tmp/bar', (err, files_and_directories) => {
  if (err) {
    console.error(err)
  } else {
    console.log(files_and_directories)
  }
})

 

The output from fs.readdirSync (not asynchronous) would be something like this, where the first list will be all of the files and sub-directories in /tmp/foo and the second list will be the files in /tmp/bar.

[
  '0.txt',  '1.txt',  '10.txt', '11.txt', '12.txt', '13.txt',
  '14.txt', '15.txt', '16.txt', '17.txt', '18.txt', '19.txt',
  '2.txt',  '20.txt', '21.txt', '22.txt', '23.txt', '24.txt',
  '25.txt', '26.txt', '27.txt', '28.txt', '29.txt', '3.txt',
  '30.txt', '31.txt', '32.txt', '33.txt', '34.txt', '35.txt',
  '36.txt', '37.txt', '38.txt', '39.txt', '4.txt',  '40.txt',
  '41.txt', '42.txt', '43.txt', '44.txt', '45.txt', '46.txt',
  '47.txt', '48.txt', '49.txt', '5.txt',  '50.txt', '51.txt',
  '52.txt', '53.txt', '54.txt', '55.txt', '56.txt', '57.txt',
  '58.txt', '59.txt', '6.txt',  '60.txt', '61.txt', '62.txt',
  '63.txt', '64.txt', '65.txt', '66.txt', '67.txt', '68.txt',
  '69.txt', '7.txt',  '70.txt', '71.txt', '72.txt', '73.txt',
  '74.txt', '75.txt', '76.txt', '77.txt', '78.txt', '79.txt',
  '8.txt',  '80.txt', '81.txt', '82.txt', '83.txt', '84.txt',
  '85.txt', '86.txt', '87.txt', '88.txt', '89.txt', '9.txt',
  '90.txt', '91.txt', '92.txt', '93.txt', '94.txt', '95.txt',
  '96.txt', '97.txt', '98.txt', '99.txt',
  ... 9999 more items
]
[ 'hello.txt', 'world.txt' ]

 

On the other hand, fs.readdir (asynchronous) would probably first return the files in the /tmp/bar directory because it should take much less time for this block to complete and then the list of files and sub-directories in the /tmp/foo directory would come next.

[ 'hello.txt', 'world.txt' ]
[
  '0.txt',  '1.txt',  '10.txt', '11.txt', '12.txt', '13.txt',
  '14.txt', '15.txt', '16.txt', '17.txt', '18.txt', '19.txt',
  '2.txt',  '20.txt', '21.txt', '22.txt', '23.txt', '24.txt',
  '25.txt', '26.txt', '27.txt', '28.txt', '29.txt', '3.txt',
  '30.txt', '31.txt', '32.txt', '33.txt', '34.txt', '35.txt',
  '36.txt', '37.txt', '38.txt', '39.txt', '4.txt',  '40.txt',
  '41.txt', '42.txt', '43.txt', '44.txt', '45.txt', '46.txt',
  '47.txt', '48.txt', '49.txt', '5.txt',  '50.txt', '51.txt',
  '52.txt', '53.txt', '54.txt', '55.txt', '56.txt', '57.txt',
  '58.txt', '59.txt', '6.txt',  '60.txt', '61.txt', '62.txt',
  '63.txt', '64.txt', '65.txt', '66.txt', '67.txt', '68.txt',
  '69.txt', '7.txt',  '70.txt', '71.txt', '72.txt', '73.txt',
  '74.txt', '75.txt', '76.txt', '77.txt', '78.txt', '79.txt',
  '8.txt',  '80.txt', '81.txt', '82.txt', '83.txt', '84.txt',
  '85.txt', '86.txt', '87.txt', '88.txt', '89.txt', '9.txt',
  '90.txt', '91.txt', '92.txt', '93.txt', '94.txt', '95.txt',
  '96.txt', '97.txt', '98.txt', '99.txt',
  ... 9999 more items
]

 

In Node.js version 20 and above, recursive: true can be used to do a recursive search for all files and directories at and below the base target directory.

import fs from "fs"

const base_directory = '/tmp'
const files_and_directories = fs.readdirSync(base_directory, {recursive: true})

console.log(files_and_directories)

 

forEach can be used to loop through the list.

import fs from "fs"

const base_directory = '/tmp'
const files_and_directories = fs.readdirSync(base_directory, {recursive: true}).forEach(item => {
  console.log(item)
})

 

fs.lstatSync can be used to return the stats of each item to determine if the item . . . 

  • isFile()
  • isDirectory()
  • isSymbolicLink()
  • isFIFO()
  • isSocket()
  • isCharacterDevice()
  • isBlockDevice()

For example, this will only return files.

import fs from "fs"

const base_directory = '/tmp'

fs.readdirSync(base_directory, {recursive: true}).forEach(item => {
  const full_path_to_item = base_directory + '/' + item
  if (fs.lstatSync(full_path_to_item).isFile()) {
    console.log(full_path_to_item)
  }
})

 

Since files may be deleted in the midst of this block (such as with temp files) there is a possibility that something like "no such file or directory" could be returned so I'd include fs.existsSync to re-check if the file or directory still exists.

import fs from "fs"

const base_directory = '/tmp'

fs.readdirSync(base_directory, {recursive: true}).forEach(item => {
  const full_path_to_item = base_directory + '/' + item
  if (fs.exists(full_path_to_item)) {
    if (fs.lstatSync(full_path_to_item).isFile()) {
      console.log(full_path_to_item)
    }
  }
})

 

sort can be used to sort the results.

import fs from "fs"

const base_directory = '/tmp'
const files = fs.readdirSync(base_directory, {recursive: true}).filter(item => fs.lstatSync(base_directory + '/' + item).isFile()).sort()

files.forEach(item => {
  console.log(item)
})

 

RegExp can be used to only return files that match a regular expression. In this example, only files ending in .txt will be appended to the txt_files list.

import fs from "fs"

const base_directory = '/tmp'
const re = new RegExp(/\.txt$/)
const txt_files = []
const files = fs.readdirSync(base_directory, {recursive: true}).filter(item => fs.lstatSync(base_directory + '/' + item).isFile()).sort()

files.forEach(item => {
  if (re.test(item)) {
    txt_files.push(item)
  }
})

txt_files.forEach(item => {
  console.log(item)
})

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter 3c07c7 in the box below so that we can be sure you are a human.