递归遍历指定目录‌生成聚合文件‌ 的 Node.js 脚本

127 阅读2分钟

一、代码核心作用

  1. 目录遍历

    • 递归扫描 ./src 目录及其子目录
    • 自动跳过图片文件 (.png.jpg 等)、字体文件 (.ttf.woff 等) 和 Markdown 文件 (.md)
  2. 内容聚合

    • 读取所有文本类型文件内容 (如 .js.html.css 等)

    • 过滤空行后按以下格式记录每个文件:

      File: 文件名路径
      
      Content:
      文件内容(保留非空行)
      
      ---
      
  3. 文件分割

    • 当累计行数超过阈值(默认 15000 行)时:

      • 将已收集的内容写入 output_序号.txt 文件
      • 重置计数器和缓存,继续处理剩余文件

二、关键代码逻辑说明

1. 文件筛选机制

// 跳过图片文件
if (['.png', '.jpg', ..., '.svg'].includes(ext)) continue;

// 跳过字体文件
if (['.ttf', '.otf', ..., '.eot'].includes(ext)) continue;

// 跳过Markdown
if (['.md'].includes(ext)) continue;

2. 行数统计与分割

// 按非空行统计
const lines = content.split('\n').filter(line => line.trim() !== '');
lineCount += lines.length;

// 超过阈值时触发写入
if (lineCount > totalLines) break;

3. 输出文件格式

// 每个文件的记录格式
`File: ${item.filename}\n\nContent:\n${item.content}\n\n---\n`

三、典型使用场景

  1. 代码仓库分析

    • 将项目源代码聚合为可搜索的文本档案
  2. 日志处理

    • 合并分散的日志文件并按大小分割存储
  3. 文档预处理

    • 为 NLP 任务准备训练语料库

四、执行示例

假设 ./src 包含:

src/
  app.js (30行)
  utils/
    math.js (20行)
    config.json (10行)

运行后生成 output_1.txt

File: src/app.js

Content:
const fs = require('fs');
...(其他非空行)

---
File: src/utils/math.js

Content:
function add(a, b) {
...(其他非空行)

---

五、代码

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

// 异步遍历目录函数,接受目录路径和总行数作为参数
const traverseDirectory = async (dirPath, totalLines = 4000) => {
  let allResults = [] // 存储所有文件的结果
  let lineCount = 0 // 当前文件的行数计数
  let fileIndex = 1 // 输出文件的索引

  // 将当前结果写入文件的函数
  const writeToFile = () => {
    if (allResults.length > 0) {
      const output = allResults
        .map((item) => `File: ${item.filename}\n\nContent:\n${item.content}\n\n---\n`)
        .join('\n')
      fs.writeFileSync(`output_${fileIndex}.txt`, output)
      fileIndex++
      allResults = []
      lineCount = 0
    }
  }

  // 递归遍历目录的函数
  const traverse = async (currentPath) => {
    const files = fs.readdirSync(currentPath) // 读取当前目录中的所有文件

    for (const file of files) {
      const fullPath = path.join(currentPath, file) // 获取文件的完整路径
      const stat = fs.statSync(fullPath) // 获取文件的状态信息

      if (stat.isDirectory()) {
        await traverse(fullPath) // 如果是目录,递归遍历
      } else {
        const ext = path.extname(fullPath).toLowerCase() // 获取文件扩展名
        if (['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg'].includes(ext)) {
          continue // 忽略图片文件
        }

        if (['.ttf', '.otf', '.woff', '.woff2', '.eot', '.svg'].includes(ext)) {
          continue // 忽略字体文件
        }

        if (['.md'].includes(ext)) {
          continue // 忽略markdown文件
        }

        const content = fs.readFileSync(fullPath, 'utf8') // 读取文件内容
        const lines = content.split('\n').filter((line) => line.trim() !== '') // 按行分割并过滤空行

        allResults.push({
          filename: fullPath,
          content: lines.join('\n'),
        })
        lineCount += lines.length // 更新行数计数

        if (lineCount > totalLines) {
          break // 如果当前文件的行数超过总行数,停止遍历
        }
      }
    }
  }

  await traverse(dirPath) // 开始遍历指定目录

  // 写入剩余内容
  writeToFile()
}

// 使用示例
const targetDirectory = './src'
const totalLines = 15000 // 生成文件的总行数
traverseDirectory(targetDirectory, totalLines)