Reputation: 135
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?
Upvotes: 1
Views: 372
Reputation: 135217
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))
: []
)
]
Upvotes: 2
Reputation: 32145
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"
.
Upvotes: 0