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

如何将目录下JSON文件内容读取为对象数组?Node.js异步问题求助

解决Node.js/Express中异步读取目录下JSON文件的问题

你说得完全对,问题核心就是异步操作的执行顺序——fs.readdir是异步方法,它的回调还没跑完,你后面遍历fileNames的代码就已经执行了,这时候fileNames还是空数组,自然读不到文件。另外你的代码里还有几个小细节需要修正,我一步步给你讲清楚:

先梳理你代码里的几个小问题

  • files.forEach的用法错了:forEach不会返回新数组,而且你在循环里又fileNames.push(file),这会导致文件名重复添加。其实直接fileNames = files就可以拿到所有文件名。
  • 编码拼写错误:'uft8'应该是'utf8',不然读取文件会报错。
  • 文件路径问题:读取文件时要带上目录路径${dataFolder}/${fileName},不然Node会在当前执行目录找文件,而不是你指定的parsed_json_data文件夹。

方案一:用回调嵌套(基础写法)

把读取文件的逻辑放到fs.readdir的回调里,确保拿到文件名后再执行读取操作:

const express = require('express')
const app = express()
const port = 3001
const fs = require('fs')
const dataFolder = './parsed_json_data'
let fileObjects = []

fs.readdir(dataFolder, (err, files) => {
  if (err) {
    return console.log('读取目录失败:', err)
  }
  // 过滤出JSON文件(可选,避免读取非JSON文件)
  const jsonFiles = files.filter(file => file.endsWith('.json'))
  
  let completedReads = 0
  jsonFiles.forEach(fileName => {
    const filePath = `${dataFolder}/${fileName}`
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) {
        console.log(`读取文件${fileName}失败:`, err)
        completedReads++
        return
      }
      try {
        const jsonObj = JSON.parse(data)
        fileObjects.push(jsonObj)
      } catch (parseErr) {
        console.log(`解析${fileName}的JSON失败:`, parseErr)
      }
      completedReads++
      // 所有文件都读取完成后,可以做后续操作
      if (completedReads === jsonFiles.length) {
        console.log('所有JSON文件读取完成:', fileObjects)
      }
    })
  })
})

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

方案二:用Promise + async/await(推荐,更清晰)

Node.js的fs模块有Promise版本(fs.promises),用async/await可以让异步代码看起来像同步代码,解决你之前没成功的问题:

const express = require('express')
const app = express()
const port = 3001
const fs = require('fs').promises // 用Promise版本的fs
const path = require('path') // 用path模块处理路径更可靠
const dataFolder = './parsed_json_data'
let fileObjects = []

// 封装一个读取并解析单个JSON文件的函数
async function readAndParseJson(filePath) {
  try {
    const data = await fs.readFile(filePath, 'utf8')
    return JSON.parse(data)
  } catch (err) {
    console.log(`处理文件${filePath}失败:`, err)
    return null // 出错时返回null,不影响整体
  }
}

// 主逻辑用async函数
async function loadAllJsonFiles() {
  try {
    // 先读取目录下的所有文件
    const files = await fs.readdir(dataFolder)
    // 过滤JSON文件,生成完整路径
    const jsonFilePaths = files
      .filter(file => file.endsWith('.json'))
      .map(file => path.join(dataFolder, file)) // 用path.join避免路径拼接的问题
    
    // 并行读取所有JSON文件(效率更高)
    const jsonObjects = await Promise.all(jsonFilePaths.map(readAndParseJson))
    // 过滤掉null(出错的文件)
    fileObjects = jsonObjects.filter(obj => obj !== null)
    
    console.log('所有JSON文件加载完成:', fileObjects)
  } catch (err) {
    console.log('加载JSON文件失败:', err)
  }
}

// 调用加载函数
loadAllJsonFiles()

app.get('/', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

这个方案的优势:

  • 用fs.promises替代回调,代码更简洁易读。
  • 用Promise.all并行读取所有文件,比逐个读取效率更高。
  • 用path.join处理路径,避免不同操作系统下的路径分隔符问题(比如Windows是\,Linux是/)。
  • 加入了错误处理,单个文件出错不会导致整个流程崩溃。

额外提示

如果你的Express接口需要返回这些JSON数据,可以把加载逻辑放到路由里,或者确保在接口被调用前已经加载完成(比如用await loadAllJsonFiles()后再启动服务器)。

内容的提问来源于stack exchange,提问作者Kristoffer Tølbøll

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:43:58