一、思路
1. 找出代码文件
项目中的文件琳琅满目,我们需要在所有文件中找出代码文件,则需要过滤掉不符合条件的文件夹或文件。读取时,需要对项目文件夹进行递归,找出所有符合条件的代码文件,等待使用。
2. 逐行读取每个代码文件,统计行数
要想统计代码行数,则必然要读取代码文件的文本内容,我们选择逐行读取的方式(其实对应了比较大的缓冲区而已),如果读取到的行不是空行,则记录一个有效行数(还可以将规则设置的更严格,例如一行至少需要5个文字才计算在内)。最后,将读取到的所有代码文件的行数汇总,即为项目中的代码文件行数。
二、实现
以下封装了两个基础函数,一个用于递归读取项目下的文件,并可以设置过滤规则。另一个则是逐行读取文件内容,统计文件行数。
var fs = require('fs')
var { join } = require('path')
var readline = require('readline')
/**
* 读取项目中的所有文件(除符合过滤条件的文件外)
* @param {String} path 项目路径
* @param {...any} filters 过滤条件,符合的条件将会过滤,可过滤目录或文件
*/
function readFiles(path, ...filters) {
var allFiles = []
doRead(path)
function doRead(path) {
var files = fs.readdirSync(path, {
withFileTypes: true
})
files.forEach(file => {
var pass = filters.some(filter => filter(file))
if (!pass) {
if (file.isDirectory()) {
doRead(join(path, file.name))
} else {
allFiles.push({
path: join(path, file.name)
})
}
}
})
}
return allFiles
}
/**
* 统计文件行数
* @param {String} path 文件路径,如d:/1.txt
* @param {Function} callback 回调
*/
function statLines(path, callback) {
let total = 0
const rl = readline.createInterface({
input: fs.createReadStream(path)
})
rl.on('line', line => {
total++
})
rl.once('close', () => {
callback(null, total)
})
}
module.exports = {
readFiles,
statLines
}
接下来,通过对上述两个通用函数的调用,统计总行数。
var { readFiles, statLines } = require('./file')
var files = readFiles('/project', file => {
return file.isDirectory() && (file.name === 'node_modules' || file.name === 'public')
}, file => {
return file.isFile() && !/(vue|js)$/.test(file.name)
})
var total = 0
var run = 0, need = files.length
files.forEach(file => {
statLines(file.path, (err, count) => {
total += count
if (++run >= need) {
console.log(total)
}
})
})