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

如何在NodeJS中读取目录下程序文件内容并生成内容数组

优化目录文件内容读取方案(解决大文件内存问题与异步逻辑缺陷)

原代码存在的核心问题

  • 错误处理逻辑失效:if(err)分支错误地将data(此时为undefined)推入数组,未正确捕获或跳过错误文件
  • 异步索引混乱:for循环的i在异步回调执行时已被修改,导致console.log(directoryFileContents[i])无法输出对应文件的内容
  • 大文件内存压力:fs.readFile会一次性将整个文件加载到内存,处理package-lock.json这类大体积文件时,极易引发内存占用过高问题

推荐优化方案

方案1:使用fs.promises + async/await(异步非阻塞,可控制并发)

采用Promise化的文件API,配合async/await简化异步逻辑,同时通过并发数限制避免同时读取多个大文件导致内存暴涨:

const fs = require('fs').promises;
const path = require('path');

async function readAllFiles(directory, directoryFiles) {
    const directoryFileContents = [];
    // 限制并发读取数,根据内存情况调整
    const concurrencyLimit = 3;
    let activeTasks = 0;
    const taskQueue = [];

    // 生成所有读取任务
    for (const filename of directoryFiles) {
        const filePath = path.join(directory, filename);
        taskQueue.push(async () => {
            try {
                const data = await fs.readFile(filePath, 'utf-8');
                directoryFileContents.push({ filename, content: data });
            } catch (err) {
                console.error(`读取失败:${filePath}`, err.message);
                // 可选择记录错误或跳过错误文件
                directoryFileContents.push({ filename, error: err.message });
            }
        });
    }

    // 控制并发执行任务
    for (const task of taskQueue) {
        if (activeTasks >= concurrencyLimit) {
            await new Promise(resolve => setImmediate(resolve));
        }
        activeTasks++;
        task().finally(() => activeTasks--);
    }

    // 等待所有任务完成
    while (activeTasks > 0) {
        await new Promise(resolve => setImmediate(resolve));
    }

    return directoryFileContents;
}

// 使用示例
// readAllFiles('./your-project-dir', ['index.js', 'package-lock.json'])
//   .then(contents => console.log('所有文件内容:', contents));

方案2:流式读取(针对超大文件)

如果不需要将完整文件内容存入数组,或可分块处理,用流式读取能大幅降低内存占用:

const fs = require('fs');
const path = require('path');

// 流式读取单个文件并拼接内容
function readFileStream(filePath) {
    return new Promise((resolve, reject) => {
        let content = '';
        const stream = fs.createReadStream(filePath, 'utf-8');
        
        stream.on('data', chunk => {
            content += chunk;
            // 可在此处添加分块处理逻辑,无需等待文件读完
        });
        stream.on('end', () => resolve(content));
        stream.on('error', err => reject(err));
    });
}

// 结合async/await批量读取,用法同方案1

方案3:回调风格的基础修正(兼容旧代码)

如果必须保留回调写法,需修复索引问题和错误处理:

const fs = require('fs');
const path = require('path');

const directoryFileContents = [];
let completedReads = 0;
const totalFiles = directoryFiles.length;

for (let i = 0; i < totalFiles; i++) {
    // 用闭包保存当前文件索引
    (function(fileIndex) {
        const filePath = path.join(directory, directoryFiles[fileIndex]);
        fs.readFile(filePath, 'utf-8', (err, data) => {
            completedReads++;
            if (err) {
                console.error(`读取失败:${filePath}`, err.message);
                directoryFileContents[fileIndex] = { error: err.message };
            } else {
                directoryFileContents[fileIndex] = data;
            }
            // 所有文件读取完成后执行后续逻辑
            if (completedReads === totalFiles) {
                console.log('全部读取完成:', directoryFileContents);
            }
        });
    })(i);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:04:52