-
-
Save lovasoa/8691344 to your computer and use it in GitHub Desktop.
// ES6 version using asynchronous iterators, compatible with node v10.0+ | |
const fs = require("fs"); | |
const path = require("path"); | |
async function* walk(dir) { | |
for await (const d of await fs.promises.opendir(dir)) { | |
const entry = path.join(dir, d.name); | |
if (d.isDirectory()) yield* walk(entry); | |
else if (d.isFile()) yield entry; | |
} | |
} | |
// Then, use it with a simple async for loop | |
async function main() { | |
for await (const p of walk('/tmp/')) | |
console.log(p) | |
} |
// Callback-based version for old versions of Node | |
var fs = require("fs"), | |
path = require("path"); | |
function walk(dir, callback) { | |
fs.readdir(dir, function(err, files) { | |
if (err) throw err; | |
files.forEach(function(file) { | |
var filepath = path.join(dir, file); | |
fs.stat(filepath, function(err,stats) { | |
if (stats.isDirectory()) { | |
walk(filepath, callback); | |
} else if (stats.isFile()) { | |
callback(filepath, stats); | |
} | |
}); | |
}); | |
}); | |
} | |
if (exports) { | |
exports.walk = walk; | |
} else { | |
walk(".", manageFile); | |
} |
I'm just getting started with node so I'm sure the answer is straight forward so forgive me...but if I enter the May 11 code first it won't accept the await
part of for await (const p of walk('/tmp/'))
. If I remove that it will run then throw an exception on the walk
part of that same line saying its not a function or its return value is no iterable. Too many concepts coming at me at once "p so I don't even know where to start in terms of figuring out these errors. Any help?
if I enter the May 11 code first
I'm not sure I understand that...
it won't accept the
await
part offor await (const p of walk('/tmp/'))
I guess you are either using an old version version of node or you are trying to use for await
outside of an async function.
Here are a few articles you can read to get started :
- about async/await in general : https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
- about
for await
: https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js.html - about why
for await
is not accepted outside of anasync
function: https://v8.dev/features/top-level-await
I'm using Node 12 according to node -v
It just looked like the two parts of the May 11 comment were a standalone I could just run but thanks for the links I'll see if I can work it out!
You can easily turn it into a standalone, just wrap the top-level code in an async function:
async function* walk(dir) {
for await (const d of await fs.promises.opendir(dir)) {
const entry = path.join(dir, d.name);
if (d.isDirectory()) yield* await walk(entry);
else if (d.isFile()) yield entry;
}
}
async function main() {
for await (const p of walk('/tmp/'))
console.log(p)
}
main()
Or do it all in one, like:
( async () => {
for await (const p of walk('/tmp/'))
console.log(p)
} )();
Here's an es6 version
const fs = require('fs').promises; const path = require('path'); async function walk(dir) { let files = await fs.readdir(dir); files = await Promise.all(files.map(async file => { const filePath = path.join(dir, file); const stats = await fs.stat(filePath); if (stats.isDirectory()) return walk(filePath); else if(stats.isFile()) return filePath; })); return files.reduce((all, folderContents) => all.concat(folderContents), []); }
I searched for this a lot of time , Thanks ;)
Any idea how to control parallel number?
Synchronous version:
const walkSync = (dir, callback) => { const files = fs.readdirSync(dir); files.forEach((file) => { var filepath = path.join(dir, file); const stats = fs.statSync(filepath); if (stats.isDirectory()) { walkSync(filepath, callback); } else if (stats.isFile()) { callback(filepath, stats); } }); };
@acidic9 just curious, is there a reason for a var
on line 4 or it's just an oversight? The rest of places uses const
, just seems like it could've been intentional :)
For fun, here is the ES6/Promises version with an added simple file-type filter:
async walk(dir, ftype) {
let files = await fs.readdir(dir)
files = await Promise.all(files.map(async file => {
const filePath = path.join(dir, file)
const stats = await fs.stat(filePath)
if (stats.isDirectory()) {
return this.walk(filePath, ftype)
} else if (stats.isFile() && file.endsWith(ftype)) {
return filePath
}
}))
// Filter out undefined entries before concatenating
return files.filter(Boolean).reduce((all, folderContents) => all.concat(folderContents), [])
}
Oh, and a minor correction to how you use it. Fairly sure you should have the inner await not just the outer:
for await (const p of await walk(folder, '.html')) {
console.log(p)
}
Ah yes, very good point.