nodejs表示fs将文件迭代成数组或对象失败

所以我试图使用nodejs express FS模块来迭代我的应用程序中的目录,将每个文件名存储在一个数组中,我可以传递给我的快速查看并遍历列表,但Im努力这样做。 当我在files.forEach函数循环中做一个console.log时,它打印文件名就好了,但只要我尝试做任何事情,例如:

var myfiles = []; var fs = require('fs'); fs.readdir('./myfiles/', function (err, files) { if (err) throw err; files.forEach( function (file) { myfiles.push(file); }); }); console.log(myfiles); 

它失败了,只是logging一个空的对象。 所以我不确定究竟发生了什么事情,我认为这跟callback函数有关,但是如果有人能够引导我通过我做错了什么,为什么它不工作(以及如何使它工作),那将是非常感激。

myfiles数组是空的,因为在调用console.log()之前没有调用callback函数。

您需要执行以下操作:

 var fs = require('fs'); fs.readdir('./myfiles/',function(err,files){ if(err) throw err; files.forEach(function(file){ // do something with each file HERE! }); }); // because trying to do something with files here won't work because // the callback hasn't fired yet. 

请记住,节点中的所有内容都是同时发生的,因为除非在callback函数中进行处理,否则不能保证asynchronous函数已经完成。

解决这个问题的一个办法就是使用EventEmitter:

 var fs=require('fs'), EventEmitter=require('events').EventEmitter, filesEE=new EventEmitter(), myfiles=[]; // this event will be called when all files have been added to myfiles filesEE.on('files_ready',function(){ console.dir(myfiles); }); // read all files from current directory fs.readdir('.',function(err,files){ if(err) throw err; files.forEach(function(file){ myfiles.push(file); }); filesEE.emit('files_ready'); // trigger files_ready event }); 

fs.readdir是asynchronous的(与node.js中的许多操作一样)。 这意味着console.log行将在readdir有机会调用传递给它的函数之前运行。

您需要:

console.log行放在给readdir的callback函数中,即:

 fs.readdir('./myfiles/', function (err, files) { if (err) throw err; files.forEach( function (file) { myfiles.push(file); }); console.log(myfiles); }); 

或者只需对forEach每个文件执行一些操作即可。

正如前面提到的,你正在使用一个asynchronous方法,所以你有一个不确定的执行path。

但是,有一个简单的方法来解决这个问题。 只需使用该方法的同步版本即可:

 var myfiles = []; var fs = require('fs'); var arrayOfFiles = fs.readdirSync('./myfiles/'); //Yes, the following is not super-smart, but you might want to process the files. This is how: arrayOfFiles.forEach( function (file) { myfiles.push(file); }); console.log(myfiles); 

这应该是你想要的。 但是,使用同步语句并不好,所以你不应该这样做,除非它是同步非常重要的。

在这里阅读更多: fs.readdirSync

我认为这与callback函数有关,

究竟。

fs.readdir向文件系统发出一个asynchronous请求,并在稍后调用callback和结果。

所以function (err, files) { ... }不会立即运行,而是console.log(myfiles)

在稍后的时间点, myfiles将包含所需的信息。

你应该注意到BTW files已经是一个数组了,所以把每个元素手动添加到其他空白数组是没有任何意义的。 如果想法是把几个调用的结果放在一起,那么使用.concat ; 如果你只想获得一次数据,那么你可以直接分配myfiles = files

总的来说,你真的应该阅读“延续传球风格” 。

我面临同样的问题,根据这篇文章给出的答案,我已经用Promise解决了这个问题,在这种情况下似乎是非常完美的:

 router.get('/', (req, res) => { var viewBag = {}; // It's just my little habit from .NET MVC ;) var readFiles = new Promise((resolve, reject) => { fs.readdir('./myfiles/',(err,files) => { if(err) { reject(err); } else { resolve(files); } }); }); // showcase just in case you will need to implement more async operations before route will response var anotherPromise = new Promise((resolve, reject) => { doAsyncStuff((err, anotherResult) => { if(err) { reject(err); } else { resolve(anotherResult); } }); }); Promise.all([readFiles, anotherPromise]).then((values) => { viewBag.files = values[0]; viewBag.otherStuff = values[1]; console.log(viewBag.files); // logs eg [ 'file.txt' ] res.render('your_view', viewBag); }).catch((errors) => { res.render('your_view',{errors:errors}); // you can use 'errors' property to render errors in view or implement different error handling schema }); }); 

注意:您不必将find的文件推送到新的数组中,因为您已经从fs.readdir()的ccallback中获得了一个数组。 根据节点文档 :

callback函数获取两个参数(err,files) ,其中files不包含'。'的文件名的数组 。 和“..”。

我相信这是非常优雅和方便的解决scheme,最重要的是 – 它不要求您将新模块引入并处理脚本。