如何在node.js中获取目录大小而无需递归遍历目录?

use*_*401 5 fs node.js

如何在不递归地遍历目录中所有子级的情况下获取node.js中目录的大小?

例如

var fs = require('fs');
fs.statSync('path/to/dir');
Run Code Online (Sandbox Code Playgroud)

会把这样的东西还给我,

{ dev: 16777220,
  mode: 16877,
  nlink: 6,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 62403939,
  size: 204,
  blocks: 0,
  atime: Mon May 25 2015 20:54:53 GMT-0400 (EDT),
  mtime: Mon May 25 2015 20:09:41 GMT-0400 (EDT),
  ctime: Mon May 25 2015 20:09:41 GMT-0400 (EDT) }
Run Code Online (Sandbox Code Playgroud)

但是size属性不是目录的大小,而是目录的大小(即目录中文件的总和)。

如果不递归地找到子目录的大小(然后将其总和),是否没有办法获取目录的大小(包含目录中文件的大小)?

我基本上是想做等效的操作,du -ksh my-directory但是如果给定目录的确很大(例如/),则需要递归地获取真正的目录大小。

And*_*dri 19

我使用这个简单的async/await + fs Promises API (Node.js v14+) 解决方案...它不依赖于外部库或生成新进程,这很好:

const path = require('path');
const { readdir, stat } = require('fs/promises');

const dirSize = async directory => {
  const files = await readdir( directory );
  const stats = files.map( file => stat( path.join( directory, file ) ) );

  return ( await Promise.all( stats ) ).reduce( ( accumulator, { size } ) => accumulator + size, 0 );
}
Run Code Online (Sandbox Code Playgroud)

用法:

( async () => {
  const size = await dirSize( '/path/to/directory' );
  console.log( size );
} )();
Run Code Online (Sandbox Code Playgroud)

尽管它是映射/减少数组,但它不使用任何循环结构来递归目录。其他解决方案只是抽象 NPM 包/C 代码背后的递归,所以它应该都很好......


更新:我已经使用上述解决方案来获取目录,而无需根据我之前的用例递归地遍历子目录...而且,再次清楚地阅读问题,原始海报也想要子目录的大小。

如果有人正在寻找这个,这应该可以解决问题;但从技术上讲,它并不能避免递归。感谢@Inigo 的评论!

const { readdir, stat } = require('fs/promises');
const { join } = require('path');

const dirSize = async dir => {
  const files = await readdir( dir, { withFileTypes: true } );

  const paths = files.map( async file => {
    const path = join( dir, file.name );

    if ( file.isDirectory() ) return await dirSize( path );

    if ( file.isFile() ) {
      const { size } = await stat( path );
      
      return size;
    }

    return 0;
  } );

  return ( await Promise.all( paths ) ).flat( Infinity ).reduce( ( i, size ) => i + size, 0 );
}
Run Code Online (Sandbox Code Playgroud)

用法:

( async () => {
  const size = await dirSize( '/path/to/directory' );
  console.log( size );
} )();
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案根本不会通过目录进行递归,因此如果目录有子目录(可能是最重要的用例),则会给出错误的答案。这会导致投反对票,如果你修复它,我会撤回该票。 (2认同)

Sim*_*one 8

fast-fold-size使用Windows 上的Sysinternals DU和其他平台上的内置du程序来快速计算文件夹大小。

安装

npm i fast-folder-size

用法

const fastFolderSize = require('fast-folder-size')

fastFolderSize('.', (err, bytes) => {
  if (err) {
    throw err
  }

  console.log(bytes)
})
Run Code Online (Sandbox Code Playgroud)


rel*_*els 5

您可以du在目标目录上生成一个命令,但正如您所说,第一次可能会很慢。您可能不知道的是,du结果似乎以某种方式缓存了:

$ time du -sh /var
13G /var
du -sh /var  0.21s user 0.66s system 9% cpu 8.930 total
$ time du -sh /var
13G /var
du -sh /var  0.11s user 0.34s system 98% cpu 0.464 total
Run Code Online (Sandbox Code Playgroud)

最初用了 8 秒,然后只用了 0.4 秒

因此,如果您的目录不经常更改,那么使用du可能是最简单的方法。

另一种解决方案是将其存储在缓存层中,这样您就可以观察根目录的变化,然后计算文件夹的大小,将其存储在缓存中,并在需要时提供服务。要执行此操作,您可以使用 NodeJS 的监视功能,但您会遇到一些跨平台问题,因此像 chokidar 这样的库可能会有所帮助。


hmh*_*sh3 2

您应该尝试“getFolderSize”节点模块 https://www.npmjs.com/package/get-folder-size

用法

getFolderSize(folder, [regexIgnorePattern], callback)
Run Code Online (Sandbox Code Playgroud)

例子:

var getSize = require('get-folder-size');

getSize(myFolder, function(err, size) {
  if (err) { throw err; }

  console.log(size + ' bytes');
  console.log((size / 1024 / 1024).toFixed(2) + ' Mb');
});
Run Code Online (Sandbox Code Playgroud)

  • 您发布的模块正在使用递归解决方案。https://github.com/alessioalex/get-folder-size/blob/master/index.js#L7 (3认同)
  • 对于小的浅目录可能没问题。对于大而深的目录来说非常糟糕。我宁愿运行 shell 命令并让操作系统处理它。它也没有给出磁盘大小 - 这是检查文件夹大小的常见动机。 (3认同)
  • 您好,请扩展您的答案,以包含即使没有超链接也有用的解决方案。提前致谢。 (2认同)