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,最重要的是 – 它不要求您将新模块引入并处理脚本。