背景:
昨天领导找我说,有一个项目需要协助一下:找出我们平台里面所有的ajax请求的url。
因为我们的平台是商城系统,多年累积下来的项目,就js文件都大几百个,并且还是三端(web/H5/app),如果一个文件一个文件去找的话,估计需要很大的时间成本。
正好前段时间在看node知识,了解到可以通过js脚本来实现遍历文件进行读取和写入的过程。
fs模块是File System(文件系统)的缩写,它提供了一系列API用于与文件系统进行交互。你可以使用这些API来读取文件、写入文件、更改文件权限、监视文件变化等。
path模块提供了一些实用工具函数,用于处理文件和目录的路径。这些函数可以简化路径的拼接、分解、格式化和转换等工作。
readline模块用于逐行读取文件内容或来自其他可读流(如标准输入)的数据。这对于处理大型文件或需要与用户进行交互式文本输入的场景非常有用。
javascript
// 准备工作,引入需要的api
const fs = require('fs');
const path = require('path');
const readline = require('readline');
因为文件夹里面可能会存在多个文件夹或者多个文件,需要我们通过递归去遍历文件夹里面的文件
定义文件路径
javascript
// 指定要遍历的起始文件夹路径
const startDirPath = 'xxx';
// 输出文件路径,最好是采用绝对路径
const outputFilePath = 'xxx';
清空写入的文件的内容
javascript
// 使用fs.truncate清空文件内容
fs.truncate(outputFilePath, 0, () => {});
递归遍历文件内容并写入文件
javascript
traverseDirectory(startDirPath);
// 递归遍历文件夹的函数
function traverseDirectory(dirPath) {
fs.readdir(dirPath, { withFileTypes: true }, (err, files) => {
if (err) {
console.error(`Error reading directory ${dirPath}: ${err}`);
return;
}
files.forEach(file => {
const fullPath = path.join(dirPath, file.name);
if (file.isDirectory() && file.name !== 'node_modules') {
traverseDirectory(fullPath); // 递归遍历
} else if (file.isFile() && path.extname(file.name).toLowerCase() === '.js') {
// 读取JS文件
const rl = readline.createInterface({
input: fs.createReadStream(fullPath),
crlfDelay: Infinity
});
let matchedLines = [];
rl.on('line', (line) => {
// 使用正则表达式找到所有被引号包裹的字符串
const quoteRegex = /(['"])\/([\/\w]+)\1/g;
let match;
while ((match = quoteRegex.exec(line)) !== null) {
matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);
}
});
rl.on('close', () => {
// 将所有匹配的字符串写入输出文件
if (matchedLines.length > 0) {
fs.appendFile(outputFilePath, matchedLines.join('\n') + '\n', (err) => {
if (err) {
console.error(`Error writing to ${outputFilePath}: ${err}`);
} else {
console.log(outputFilePath, 'outputFilePath')
console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);
}
});
}
});
}
});
});
}
可能由于我们的正则匹配格式并没有很严谨,或者说我们只需要某些特定的数据,这个时候,我们可以对获取到的数据进行移除特定词的过滤。
javascript
// 关键词列表
const keywords = ['submit', 'add', 'update', 'save', 'confirm', 'faq', 'cn', 'page', 'list', 'send', 'join', 'modelInventory', 'mem', 'mcom', 'trade', 'order', 'corporateProcurement',
'enterprisePay', 'delete', 'cancel', 'del', 'check', 'upload'];
// 检查字符串是否包含任何关键词(不区分大小写)
function containsKeyword(str) {
return keywords.some(keyword => str && str.toLowerCase().includes(keyword));
}
// 在写入文件之前进行判断
while ((match = quoteRegex.exec(line)) !== null) {
const quotedString = match[2];
if (containsKeyword(quotedString)) {
// 如果引号内的内容包含关键词,则记录整个匹配的字符串
matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);
}
}
如果您想对获取到的数据进行排序或者做一些其他的操作,可以将输入传给外面的变量
javascript
let resultList = [];
rl.on('close', () => {
// 将所有匹配的字符串写入输出文件
if (matchedLines.length > 0) {
resultList = [...resultList, ...matchedLines];
console.log(outputFilePath, 'outputFilePath')
console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);
}
});
总结代码
javascript
const fs = require('fs');
const path = require('path');
const readline = require('readline');
// 关键词列表
const keywords = ['submit', 'add', 'update', 'save', 'confirm', 'faq', 'cn', 'page', 'list', 'send', 'join', 'modelInventory', 'mem', 'mcom', 'trade', 'order', 'corporateProcurement',
'enterprisePay', 'delete', 'cancel', 'del', 'check', 'upload'];
// 指定要遍历的起始文件夹路径
const startDirPath = 'D:\\projects\\ecm\\html\\front'; // 替换为你的文件夹路径
// 输出文件路径
const outputFilePath = 'C:\\Users\\cheney_chen\\Desktop\\中文站接口url.txt';
let resultList = [];
// 检查字符串是否包含任何关键词(不区分大小写)
function containsKeyword(str) {
return keywords.some(keyword => str && str.toLowerCase().includes(keyword));
}
// 递归遍历文件夹的函数
function traverseDirectory(dirPath) {
fs.readdir(dirPath, { withFileTypes: true }, (err, files) => {
if (err) {
console.error(`Error reading directory ${dirPath}: ${err}`);
return;
}
files.forEach(file => {
const fullPath = path.join(dirPath, file.name);
if (file.isDirectory() && file.name !== 'node_modules') {
traverseDirectory(fullPath); // 递归遍历
} else if (file.isFile() && path.extname(file.name).toLowerCase() === '.js') {
// 读取JS文件
const rl = readline.createInterface({
input: fs.createReadStream(fullPath),
crlfDelay: Infinity
});
let matchedLines = [];
rl.on('line', (line) => {
// 使用正则表达式找到所有被引号包裹的字符串
const quoteRegex = /(['"])\/([\/\w]+)\1/g;
let match;
while ((match = quoteRegex.exec(line)) !== null) {
const quotedString = match[2];
if (containsKeyword(quotedString)) {
// 如果引号内的内容包含关键词,则记录整个匹配的字符串
matchedLines.includes(match[0]) ? null : matchedLines.push(match[0]);
}
}
});
rl.on('close', () => {
// 将所有匹配的字符串写入输出文件
if (matchedLines.length > 0) {
resultList = [...resultList, ...matchedLines];
console.log(outputFilePath, 'outputFilePath')
console.log(`Processed file: ${fullPath}, ${matchedLines.length} matches found.`);
}
});
}
});
});
}
// 使用fs.truncate清空文件内容
fs.truncate(outputFilePath, 0, () => {});
traverseDirectory(startDirPath);
setTimeout(()=>{
resultList = [...new Set(resultList)];
resultList = resultList.map((item, index) => (index + 1) + '、' + item)
// 写入文件
fs.appendFile(outputFilePath, resultList.join('\n') + '\n', (err) => {
if (err) {
console.error(`Error writing to ${outputFilePath}: ${err}`);
}
});
}, 5000)