nodejs 同步递归遍历文件是非常简单的,异步递归遍历是就稍许复杂了一些
异步递归遍历可以采用类似迭代器的方式进行;首先定义一个方法,回调函数拥有三个参数 分别是 err, file, next
function travelSync(dir, callback){
}
/**
* 执行方法
*/
travelSync('E:/runs', function (e, file, next) {
//处理文件
console.log(file);
//获取下一个文件
next();
});
当遍历完一个文件夹后,需要进行遍历下一个(next)文件,并且当前目录遍历完成后,若存在父级文件夹则遍历父级文件夹的未遍历的。那怎么判断已经遍历完成 和 遍历下一个文件?需要定位当前遍历位置,且当前目录遍历完后接着遍历下一个文件夹。可以在travelSync内部定义一个 参数 i 用于记录当前位置,并在 travelSync 新增一个参数 finish 用于定位当前目录遍历完成进行遍历下一个父级目录文件
function travelSync(dir, callback, finish){
fs.readdir(dir, function (e, files) {
// i 用于定位当前遍历位置
function next(i) {
// 当i >= files 表示已经遍历完成,进行遍历下一个文件夹
if(i < files.length){
}else{
finish && finish();
}
};
});
}
当前遍历对象是目录时进行递归调用,当前的位置通过 封装在一个闭包里面 传递到 travelSync 的 finish 参数中,当子目录遍历完成后,通过执行 finish 进行遍历下一个文件(finish中记录了遍历位置)。
遍历对象为文件时将 文件对象(file) 和 当前遍历位置传递(next) 到 回调方法 callback 中,并在回调方法 callback 处理完成后,执行 next 遍历下一个文件。
当 i >= files 时 表示当前文件夹遍历完成,进行遍历父级目录执行 finish 方法,这里需要明白的是, finish 是递归调用时 传进来的方法,实际finish 方法内部调用了 next(i) 方。因为首次调用时 finish 方法 没有传入 所以 应判断 finish 是否存在。
function travelSync(dir, callback, finish){
fs.readdir(dir, function (e, files) {
// i 用于定位当前遍历位置
(function next(i) {
// 当i >= files 表示已经遍历完成,进行遍历下一个文件夹
if(i < files.length){
var pathname = path.join(dir, files[i]);
if(fs.stat(pathname, function (e, stats) {
if(stats.isDirectory()){
travelSync(pathname, callback, function () {
next(i + 1);
});
}else{
callback(e, pathname, function () {
next(i + 1);
});
}
}));
}else{
/**
* 当 i >= files.length 时,即表示当前目录已经遍历完了, 需遍历下一个文件夹
* 这里执行的时递归调用 传入的 方法 , 方法里调用了 next(i) 记录了当前遍历位置
*/
finish && finish();
}
})(0);
});
}
travelSync('E:/runs', function (e, file, next) {
//处理文件
console.log(file);
//获取下一个文件
next();
});
如此便可以进行正常的遍历了文件了,下面为完成的代码
var fs = require('fs');
var path = require('path');
function travelSync(dir, callback, finish){
fs.readdir(dir, function (e, files) {
if (e === null) {
// i 用于定位当前遍历位置
(function next(i) {
// 当i >= files 表示已经遍历完成,进行遍历下一个文件夹
if(i < files.length){
var pathname = path.join(dir, files[i]);
if(fs.stat(pathname, function (e, stats) {
if(stats.isDirectory()){
travelSync(pathname, callback, function () {
next(i + 1);
});
}else{
callback(e, pathname, function () {
next(i + 1);
});
}
}));
}else{
/**
* 当 i >= files.length 时,即表示当前目录已经遍历完了, 需遍历下一个文件夹
* 这里执行的时递归调用 传入的 方法 , 方法里调用了 next(i) 记录了当前遍历位置
*/
finish && finish();
}
})(0);
}else{
callback(e);
}
});
}
travelSync('E:/runs', function (e, file, next) {
if(e !== null){
console.log(e);
}
console.log(file);
//获取下一个文件 next 里面调用了 next(i) 记录了当前遍历位置
next();
});