You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js递归统计文件数时counter++计数错误问题求助

问题分析与解决方案

你的问题核心在于JavaScript的参数传递机制:原始类型(比如数字totalFiles)是按值传递的,而数组是按引用传递的。

当你把totalFiles作为参数传入递归函数时,每次递归调用都会创建这个数值的副本——你在递归里执行totalFiles++,修改的只是当前函数作用域内的副本,根本不会影响外层的totalFiles变量。而数组totalFilesArray是引用类型,所有递归调用共享同一个数组引用,所以push操作能正确累计所有文件。

解决方法1:用引用类型包裹计数器(最贴近你的现有代码)

把计数器放到一个对象里,因为对象是引用类型,递归时传递的是同一个对象的引用,修改对象的属性会同步到所有作用域:

const fs = require('fs')
const path = require('path')
const dir = '/Users/Username'

// 用对象包裹计数器,确保递归共享同一个引用
const counter = { total: 0 }
const totalFilesArray = []

getFilesRecursively(dir, counter, totalFilesArray)

console.log(counter.total, 'total_files_count', totalFilesArray.length, 'total_files_array_count')

function getFilesRecursively(dir, counter, totalFilesArray){
  try {
    const files = fs.readdirSync(dir)
    for (const file of files) { // 建议用for...of代替for...in,避免遍历到原型链属性
      const name = path.join(dir, file)
      try {
        const stats = fs.lstatSync(name)
        if (stats.isDirectory()) {
          getFilesRecursively(name, counter, totalFilesArray)
        } else if (stats.isFile()) {
          counter.total++ // 直接修改对象属性,所有递归共享
          totalFilesArray.push(name)
        }
      } catch(err) {
        console.error(err.message)
      }
    }
  } catch(err) {
    console.error(err.message)
  }
}

解决方法2:让递归函数返回当前目录的文件数(更函数式)

不需要传递计数器,每次递归返回当前目录下的文件总数(包括子目录的),然后在外层累加:

const fs = require('fs')
const path = require('path')
const dir = '/Users/Username'

const totalFiles = getFilesRecursively(dir)
console.log(totalFiles, 'total_files_count')

function getFilesRecursively(dir){
  let count = 0
  try {
    const files = fs.readdirSync(dir)
    for (const file of files) {
      const name = path.join(dir, file)
      try {
        const stats = fs.lstatSync(name)
        if (stats.isDirectory()) {
          count += getFilesRecursively(name) // 累加子目录的文件数
        } else if (stats.isFile()) {
          count++
        }
      } catch(err) {
        console.error(err.message)
      }
    }
  } catch(err) {
    console.error(err.message)
  }
  return count
}

针对大目录的性能优化

你的目录有26万+文件,同步方法fs.readdirSync会阻塞Node.js的事件循环,导致进程无法处理其他任务。推荐使用异步非阻塞的方式,比如fs.promises的API:

const fs = require('fs').promises
const path = require('path')
const dir = '/Users/Username'

async function getFilesRecursively(dir){
  let count = 0
  try {
    const files = await fs.readdir(dir)
    // 并行处理所有文件,提升速度
    const promises = files.map(async file => {
      const name = path.join(dir, file)
      try {
        const stats = await fs.lstat(name)
        if (stats.isDirectory()) {
          count += await getFilesRecursively(name)
        } else if (stats.isFile()) {
          count++
        }
      } catch(err) {
        console.error(err.message)
      }
    })
    await Promise.all(promises)
  } catch(err) {
    console.error(err.message)
  }
  return count
}

// 执行并打印结果
getFilesRecursively(dir).then(total => {
  console.log(total, 'total_files_count')
})

这种异步方式不会阻塞进程,而且Promise.all可以并行处理多个文件/目录,比同步递归速度更快。

内容的提问来源于stack exchange,提问作者Systems Rebooter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:01:00