find大量的文件,并获得节点FS的总数

我build立一个节点脚本asynchronous输出一个目录的文件数和行数; 但是,我在其asynchronous控制stream程中遇到麻烦。

// Import Dependencies const fs = require('fs'); const get_dir_line_count = (dir) => { let output = { file_count: 0, file_line: 0, path: '' }; new Promise( (resolve, reject) => { fs.readdir(dir, (err, dir_contents) => { resolve(dir_contents); }); }).then( (promise_contents) => { Promise.all(promise_contents.map( (file) => { const file_path = dir + '/' + file; return new Promise( (resolve, reject) => { fs.stat(file_path, (err, stat) => { if(err || file[0] === '.') return err; if(stat.isDirectory() && file !== 'node_modules'){ get_dir_line_count(file_path); } else if(stat.isFile()){ promise_line_count(file_path) .then( (line_count) => { output.path = dir; output.file_line += line_count; output.file_count++; resolve(output); }); }; }); }).then( (resolved_output) => { console.log(resolved_output) return resolved_output; }); })); }); }; const promise_line_count = (pathToFile) => { let line_count = 0; return new Promise( (resolve, reject) => { fs.createReadStream(pathToFile) .on("data", (buffer) => { buffer.forEach( (chunk) => { if(chunk === 10) line_count++; }); }).on("end", () => { resolve(line_count); }); }); }; const directory = process.argv[2]; get_dir_line_count('./../' + directory); 

我的意图是recursion地通过输出Promise.all数组的目录。 每个数组是目录的计算数据的集合。 但是,我在Promise.all上有asynchronous控制stream问题。 如果任何人都可以提供反馈,这将是有益的。

输出:

项目= 5个文件,50行

Project / src = 10个文件,60行

项目/苹果= 20个文件,200行

…等等

一个问题是,你没有从get_dir_line_count函数本身返回任何东西:

 const get_dir_line_count = (dir) => { let output = { file_count: 0, file_line: 0, path: '' }; new Promise( (resolve, reject) => { // ^---- missing a return statement 

另一个问题是你忘了从Promise.all返回结果,所以链可以正确的build立:

 // ... }).then( (promise_contents) => { Promise.all(promise_contents.map( (file) => { // ^---- missing a return 

您也忘记将recursion调用返回(或parsing)为get_dir_line_count

 if(err || file[0] === '.') return err; if(stat.isDirectory() && file !== 'node_modules'){ get_dir_line_count(file_path); // ^--- missing a return statement or resolve statement } 

最后,由于您是从get_dir_line_count返回输出对象的, get_dir_line_count可以通过添加then将结果传递到console.log来检查工作:

 const directory = process.argv[2]; get_dir_line_count('./../' + directory).then(console.log) // <-- get the output object and the log it 

就处理asynchronous代码的复杂性而言,清理控制stream程的主要目的是将各个逻辑抽取为不同的function。

贝娄你可以find一个方法的代码示例以及embedded的注释(我也保留了下划线的命名首选项):

 const fs = require('fs'); const path = require('path'); // resolves with the file names within the given directory function get_file_names(dir) { return new Promise((resolve, reject) => { fs.readdir(dir, (err, fileNames) => { if (err) return reject(err); resolve(fileNames); }); }); } // resolves with an object containing the type ('file' or 'dir') for the given file path and the file path itself: { file_path, type } function get_path_and_type(file_path) { return new Promise((resolve, reject) => { fs.stat(file_path, (err, stat) => { if (err) return reject(err); if (!stat.isDirectory() && !stat.isFile()) reject('Invalid Type'); const type = stat.isDirectory() ? 'dir' : 'file'; resolve({ file_path, type }); }); }); } // same as before, counts lines for the given file path function count_lines(file_path) { return new Promise((resolve, reject) => { let lineCount = 0; fs.createReadStream(file_path) .on("data", (buffer) => { buffer.forEach((chunk) => { if (chunk === 10) lineCount++; }); }).on("end", () => { resolve(lineCount); }).on("error", reject); }); }; function get_dir_line_count(dir) { const output = { file_count: 0, file_lines: 0, path: dir }; // get all filenames in the given directory return get_file_names(dir) // filter all file names that start with a '.' or include the string 'node_modules' .then((names) => names.filter((name) => !name.startsWith('.') && !name.includes('node_modules') ) ) // map every file name into a promise that resolves with the type for that file name within the given dir .then((names) => names.map((name) => get_path_and_type(path.join(dir, name)) .catch(console.warn) // log invalid typed files if necessary ) ).then((paths_and_types_promises) => Promise.all(paths_and_types_promises.map((promise) => promise.then(({ file_path, type }) => { if (type === 'dir') { // if current file path corresponds to a directory // recursive count its files and lines and add it to the overall output return get_dir_line_count(file_path) .then((recursive_output) => { output.file_count += recursive_output.file_count; output.file_lines += recursive_output.file_count; }); } else { // count the lines for the current file path and then update the overall output return count_lines(file_path) .then((file_lines) => { output.file_lines += file_lines; output.file_count += 1; }) } }) )) // this last chain makes sure we wait for the promise to resolve // and populate the output object before resolving with it ).then(() => output); } get_dir_line_count(process.argv[2]) .then(console.log); 
 const fs = require('fs'); const path = require('path'); let output = {}; let lastDir = ''; const walk = (dir) => { return new Promise((resolve, reject) => { output[dir] = { files: 0, lines: 0, path: '' }; fs.readdir(dir, (err, list) => { if (err) { return reject(err); } let pending = list.length; if (!pending) { return resolve(output); } list.forEach((file) => { file = path.resolve(dir, file); fs.stat(file, (err, stat) => { if (stat && stat.isDirectory()) { walk(file) .then((res) => { if (!--pending) { resolve(output); } }) } else { let lc = 0; fs.createReadStream(file) .on('data', (buffer) => { buffer.forEach((chunk) => { if (chunk === 10) { lc++; } }) }) .on('end', () => { output[dir].files++; output[dir].lines += lc; output[dir].path = dir; if (!--pending) { resolve(output); } }); } }) }) }) }); }; walk('.') .then(console.log) .catch(console.log);