Last active
September 9, 2023 13:43
-
-
Save qwtel/fd82ab097cbe1db50ded9505f183ccb8 to your computer and use it in GitHub Desktop.
[node.js 8+] Recursively get all files in a directory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Node 8+ | |
// -------------------------------------------------------------- | |
// No external dependencies | |
const { promisify } = require('util'); | |
const { resolve } = require('path'); | |
const fs = require('fs'); | |
const readdir = promisify(fs.readdir); | |
const stat = promisify(fs.stat); | |
async function getFiles(dir) { | |
const subdirs = await readdir(dir); | |
const files = await Promise.all(subdirs.map(async (subdir) => { | |
const res = resolve(dir, subdir); | |
return (await stat(res)).isDirectory() ? getFiles(res) : res; | |
})); | |
return files.reduce((a, f) => a.concat(f), []); | |
} | |
// Usage | |
getFiles(__dirname) | |
.then(files => console.log(files)) | |
.catch(e => console.error(e)); | |
// Node 10.10+ | |
// -------------------------------------------------------------- | |
// Updated for node 10+ with even more whizbang: | |
const { resolve } = require('path'); | |
const { readdir } = require('fs').promises; | |
async function getFiles(dir) { | |
const dirents = await readdir(dir, { withFileTypes: true }); | |
const files = await Promise.all(dirents.map((dirent) => { | |
const res = resolve(dir, dirent.name); | |
return dirent.isDirectory() ? getFiles(res) : res; | |
})); | |
return Array.prototype.concat(...files); | |
} | |
// Note that starting with node 11.15.0 you can use | |
// `files.flat()` instead of `Array.prototype.concat(...files)` | |
// to flatten the array. | |
// Node 11+ | |
// -------------------------------------------------------------- | |
// The following version uses async iterators. | |
const { resolve } = require('path'); | |
const { readdir } = require('fs').promises; | |
async function* getFiles(dir) { | |
const dirents = await readdir(dir, { withFileTypes: true }); | |
for (const dirent of dirents) { | |
const res = resolve(dir, dirent.name); | |
if (dirent.isDirectory()) { | |
yield* getFiles(res); | |
} else { | |
yield res; | |
} | |
} | |
} | |
// Usage has changed because the return type is now an | |
// async iterator instead of a promise: | |
(async () => { | |
for await (const f of getFiles('.')) { | |
console.log(f); | |
} | |
})() | |
// I've written more about async iterators here: | |
// https://qwtel.com/posts/software/async-generators-in-the-wild/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@mrchief
Thanks! I got completely hung up on the resolve and missed the reference to the path module.
I'm trying to adapt this using a Mozilla Thunderbird DirectoryInterator as opposed to readDir.
I have been trying every possible combination of promise handling , but I am obviously flummoxed.
Removing the unnecessary path combination in my case still fails.
I'm going to keep experimenting but I may post my best if I can't get it. This approach is certainly what I need to use just with some tweaks that Confound me.