1

I want to get all directories synchronize within a given directory.

<MyFolder>
    |- Folder1
       |- Folder11
       |- Folder12
    |- Folder2
    |- File1.txt
    |- File2.txt
    |- Folder3
        |- Folder31
        |- Folder32

I would expect to get an array of:

["Folder1/Folder11", "Folder1/Folder12", "Folder2", "Folder3/Folder31", "Folder3/Folder32"]

This is my code:

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

function flatten(lists) {
  return lists.reduce((a, b) => a.concat(b), []);
}

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath)
  .map(file => path.join(srcpath, file))
  .filter(path => fs.statSync(path).isDirectory());
}

function getDirectoriesRecursive(srcpath) {
  return [srcpath, ...flatten(getDirectories(srcpath).map(getDirectoriesRecursive))];
}

Would anyone help me solve the problem above?

2
  • You need to format the elements in the returned array , iterate it and do the formatting on the elements and create new array from the formatted elements to achieve your results Commented Oct 2, 2019 at 7:10
  • The function getDirectoriesRecursive() seems to work reasonably well .. maybe you could detail exactly what's going wrong for you? When I run your code I get the output: [ '.\\', 'Folder1', 'Folder1\\Folder11', 'Folder1\\Folder12', 'Folder2', 'Folder3', 'Folder3\\Folder31', 'Folder3\\Folder32' ] Commented Oct 2, 2019 at 7:41

2 Answers 2

2

async

Here's a highly optimised version using Node's fast fs.Dirent objects. This approach allows you to skip the expensive fs.existsSync and fs.statSync calls on every path -

const { readdir } =
  require ("fs/promises")

const { join } =
  require ("path")

const dirs = async (path = ".") =>
  Promise.all
    ( (await readdir (path, { withFileTypes: true }))
        .map
          ( dirent =>
              dirent .isDirectory ()
                ? dirs (join (path, dirent.name))
                : []
          )
    )
    .then
      ( results =>
          [] .concat (path, ...results)
      )

You use it like this -

dirs ("MyFolder") .then (console.log, console.error)

sync

We can rewrite the above function using synchronous functions instead -

const { readdirSync } =
  require ("fs")

const { join } =
  require ("path")

const dirsSync = (path = ".") =>
  [].concat
    ( path
    , ...readdirSync (path, { withFileTypes: true })
        .map
          ( dirent =>
              dirent .isDirectory ()
                ? dirsSync (join (path, dirent.name))
                : []
          )
    )

You use it like this -

console .log (dirsSync ("MyFolder"))

This can be further simplified by using Array.prototype.flatMap -

const { readdirSync } =
  require ("fs")

const { join } =
  require ("path")

const dirsSync = (path = ".") =>
  [ path
  , ...readdirSync (path, { withFileTypes: true })
      .flatMap
        ( dirent =>
            dirent .isDirectory ()
              ? dirsSync (join (path, dirent.name))
              : []
        )
  ]
Sign up to request clarification or add additional context in comments.

Comments

0

You were almost there, you just need to avoid files (not directories), so the getDirectoriesRecursive(srcpath) function recursion won't throw an error.

This is how should be the final getDirectoriesRecursive code:

function getDirectoriesRecursive(srcpath) {
  return [srcpath, ...flatten(getDirectories(srcpath).map((p) => {
    try {
      if (fs.existsSync(path)) {
        if (fs.lstatSync(path).isDirectory()) {
          return getDirectoriesRecursive(path);
        }
      }
    } catch (err) {
      console.error(err)
    }
  }).filter(p => p !== undefined))];
}

This is a live working Repl Demo to show all directories inside "/opt".

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.