Nodejs异步递归文件夹大小

Posted

技术标签:

【中文标题】Nodejs异步递归文件夹大小【英文标题】:Nodejs asynchronous recursive folder size 【发布时间】:2016-03-05 03:59:59 【问题描述】:

您好,我对 javascript、Nodejs 及其异步世界还很陌生,我正在尝试以异步方式获取文件夹列表的大小(如 du 命令)。比如:

du = function(directory, callback)
    ...


displaySum = function(err, result) 
    if(!err) console.log(result);


var folders = ['/folder1', '/folder2', '/folder3'];
for (var i = 0; i < folders.length; i++) 
   du(folders[i], displaySum);

我期望以异步方式从回调中获取结果,因此当 du 完成文件夹 N 时,回调会打印出文件夹 N 的结果。

我尝试使用来自 here 的这段代码,它使用了柯里化和闭包:

//Pseudocode
duAsync4 = (dir,cb) ->
    total = 0
    file_counter = 1 #starts at one because of the initial directory
    async_running = 0

    again = (current_dir) ->
       fs.lstat current_dir, (err, stat) ->
           if err then file_counter--; return
           if stat.isFile()
               file_counter--
               total += stat.size
           else if stat.isDirectory()
               file_counter--
               async_running++
               fs.readdir current_dir, (err,files) ->
                   async_running--
                   if err then return #console.log err.message
                   file_counter += files.length
                   for file in files
                       again path.join(current_dir, file)
           else
               file_counter--
           if file_counter is 0 and async_running is 0
               cb(null, total)

again dir

我在使用 闭包 的代码中遇到的问题是,如果在第一个调用仍在进行时对 du 的第二次调用开始,那么一切都会因为闭包重复使用而变得一团糟total、file_counter 和 async_running 的当前值。

【问题讨论】:

感谢您使用 Promise 的回答,但首先我想了解异步 nodejs(使用回调)的基本概念,然后使用诸如 Promise 或 Asynch 之类的高级库。 【参考方案1】:

我觉得回调有点麻烦,所以使用Promise它仍然是异步的,希望cmets澄清事情......

var fs = require('fs')
  , path = require('path');

function getSize(dirPath)      
  return getStat(dirPath).then(function(stat)  
    if(stat.isFile())  // if file return size directly
      return stat.size;
    else
      return getFiles(dirPath).then(function(files)    // getting list of inner files
        var promises = files.map(function(file)
          return path.join(dirPath, file);  
        ).map(getSize);    // recursively getting size of each file
        return Promise.all(promises);   
      ).then(function(childElementSizes)  // success callback once all the promise are fullfiled i. e size is collected 
          var dirSize = 0;
          childElementSizes.forEach(function(size) // iterate through array and sum things
              dirSize+=size;
          );
          return dirSize;
      );
        
  );


// promisified get stats method
function getStat(filePath)
  return new Promise(function(resolve, reject)
    fs.lstat(filePath, function(err, stat)
      if(err) return reject(err);
      resolve(stat);
    );
  );


// promisified get files method
function getFiles(dir)
  return new Promise(function(resolve, reject)
    fs.readdir(dir, function(err, stat)
      if(err) return reject(err);
      resolve(stat);
    );
  );  


// example usage
getSize('example dir').then(function(size)
    console.log('dir size: ', size);
).catch(console.error.bind(console));

【讨论】:

【参考方案2】:

首先我认为你必须学习如何处理多个异步操作之前你必须寻找 Promise 或 async js 之类的库。

接下来你可以试试这样的:

var fs = require('mz/fs');

var myDir = './';

readdir(myDir)
function readdir(dir) 
  fs.readdir(dir)
    //mz fs transform all fs functions to promises
    .then(function(files) 

    //wait each promises
    return Promise.all(
      files.map(function(file) 

        return fs.lstat(file)
          .then(function(stats) 

            //the function is recursive
            if (stats.isDirectory())
              return readdir(file);
          );
      )
    )
  );

使用此代码,您可以递归查找每个子目录

【讨论】:

以上是关于Nodejs异步递归文件夹大小的主要内容,如果未能解决你的问题,请参考以下文章

nodejs 怎么获取文件大小

递归统计文件夹大小

如何在nodejs中获取文件夹大小,排除具有glob模式的某些路径?

递归求一个文件夹的大小

递归求一个文件夹大小

nodejs:遍历文件夹文件统计文件大小