将 `fs.readdir` 与 `.then` 链接以返回一个数组

Posted

技术标签:

【中文标题】将 `fs.readdir` 与 `.then` 链接以返回一个数组【英文标题】:chaining `fs.readdir` with a `.then` to return an array 【发布时间】:2017-10-16 14:08:39 【问题描述】:

我正在尝试在目录中创建一组特定文件;这将通过一些测试用例来确保它符合给定的标准。

我正在使用fs.readdir 方法,但它没有返回promise,这意味着我不能将push 传递给array

我的想法是用我实际想要输出的文件填充一个数组 (arr),然后对该数组执行一些操作。但是因为readdir 是异步的,我不能将.then() 链接到它上面,所以我的计划被取消了。

我也用readdirSync 尝试过同样的事情,但无济于事。

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

var arr = [];

fs.readdirAsync(folder).then( files => 
  files.forEach(file => 
    fs.stat(folder + '/' + file, (err, stats) => 
       if(!stats.isDirectory()) 
         arr.push(file);
        return;
      
     );
   );
)
.then( () => 
  console.log(arr);
);

【问题讨论】:

为什么不能使用回调? --- 您可以编辑您的问题以包含您的努力的minimal reproducible example 吗? “我也用 readdirSync 尝试过同样的事情,但无济于事”。该函数将返回一个文件名数组,在我看来这正是你要找的? 添加了一个我正在尝试做的例子。 arr 返回[] 【参考方案1】:

你试过fs-extra模块吗?

【讨论】:

【参考方案2】:

如果您想使用承诺而不是回调,您可以承诺 fs

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'));

fs.readdirAsync('./some').then()

http://bluebirdjs.com/docs/api/promise.promisifyall.html

【讨论】:

刚刚添加了一个我正在尝试做的示例 - 在最后一个 .then() arr 返回为 []【参考方案3】:

fs.readdir 是基于回调的,因此您可以使用 bluebird 或 Node.js utilpromisify 它(或自己编写一个简单的实现),或者简单地将调用包装在一个承诺中,就像这样:

// Wrapped in a promise
new Promise((resolve, reject) => 
    return fs.readdir('/folderpath', (err, filenames) => err != null ? reject(err) : resolve(filenames))
)

或者自定义promisify函数:

// Custom promisify
function promisify(fn) 
  /**
   * @param ...Any params The params to pass into *fn*
   * @return Promise<Any|Any[]>
   */
  return function promisified(...params) 
    return new Promise((resolve, reject) => fn(...params.concat([(err, ...args) => err ? reject(err) : resolve( args.length < 2 ? args[0] : args )])))
  


const readdirAsync = promisify(fs.readdir)
readdirAsync('./folderpath').then(filenames => console.log(filenames))

【讨论】:

我已经尝试添加一个承诺,但arr 数组仍然返回[]。我添加了一个示例,希望能澄清我在做什么。这是第一次使用readddir,所以完全有可能我用错了。 我不得不做 err !== null,但这就像一个魅力,谢谢! err ? reject(err) : resolve(filenames) => 自从 err 为我返回 null 后,第一个代码开始运行! 哦,开枪,不知道为什么我这样做了!== undefined,默认行为是返回null...更新了我的答案【参考方案4】:

我想通了;我只需要使用statSync 而不是stat

const fs = require('fs');

var arr = [];

var files = fs.readdirSync(folder);

files.forEach(file => 
  let fileStat = fs.statSync(folder + '/' + file).isDirectory();
  if(!fileStat) 
    arr.push(file);
  
);

console.log(arr);

【讨论】:

正是我所追求的。谢谢。【参考方案5】:

只是普通的 javascript,没有库:

function foo (folder, enconding) 
    return new Promise(function(resolve, reject) 
        fs.readdir(folder,enconding, function(err, filenames)
            if (err) 
                reject(err); 
            else 
                resolve(filenames);
        );
    );
;

例如

foo(someFolder, "someEncoding")
.then((files) => console.log(files))
.catch((error) => console.log(error));

【讨论】:

【参考方案6】:
new Promise((resolve, reject) => 
    return fs.readdir('/folderpath', (err, filenames) => err ? reject(err) : resolve(filenames))
)

不要err !== undefined,因为err实际上是null!!

【讨论】:

您实际上可以进一步简化它。由于您只有一个语句并且您使用的是箭头函数,因此您可以删除大括号和“return”,它会正常工作。【参考方案7】:

从 Node.js v10 开始,有一个支持此功能的 fs.promises API:

const fs = require('fs');

var arr = [];

fs.promises.readdir(folder).then( files => 
  files.forEach(file => 
    fs.stat(folder + '/' + file, (err, stats) => 
       if(!stats.isDirectory()) 
         arr.push(file);
        return;
      
     );
   );
)
.then( () => 
  console.log(arr);
);

【讨论】:

【参考方案8】:

您现在可以使用 ES6 解构赋值 (documentation):

const
    fs = require('fs'),
    FILES = [...fs.readdirSync('src/myfolder')];

console.log(FILES);

【讨论】:

真漂亮

以上是关于将 `fs.readdir` 与 `.then` 链接以返回一个数组的主要内容,如果未能解决你的问题,请参考以下文章

无法从 fs.readdir 获取 fs.Dirent 数组

使用 fs.readdir 和 fs.statSync 返回 ENOENT,没有这样的文件或目录错误

我可以等待 fs.readdir 但我不知道为啥

Node.js fs.readdir 递归目录搜索

Node.js fs.readdir 递归目录搜索

Node.js fs.readdir 递归目录搜索