Promise+async+await版本
const fs = require('fs').promises;
const path = require('path');
async function readFolderContents(folderPath) {
try {
const files = await fs.readdir(folderPath);
// 使用map方法结合Promise.all处理异步操作
const subfolders = await Promise.all(files.map(async file => {
const fullPath = path.join(folderPath, file);
const stats = await fs.stat(fullPath);
if (stats.isDirectory()) return file;
}));
// 过滤掉 undefined 元素
const filteredSubfolders = subfolders.filter(subfolder => subfolder !== undefined);
const len = filteredSubfolders.length;
const list = [];
const paddedLen = String(len).length;
for (let i = 0; i < len; i++) {
const _FN = filteredSubfolders[i];
const filePath = path.join(folderPath, _FN, 'index.html');
try {
const data = await fs.readFile(filePath, 'utf8');
const titleRegex = /<title>(.*?)<\/title>/gi;
const matches = titleRegex.exec(data);
if (matches && matches.length > 1) {
const title = matches[1];
const n = i + 1;
const obj = {
id: `id_${n}`,
index: n,
folderName: _FN,
fileName: title
};
list.push(obj);
} else {
throw new Error('Title tag not found in the HTML file.');
}
} catch (err) {
throw new Error(err);
}
}
list.sort((a, b) => a.index - b.index);
for (let i = 0; i < list.length; i++) {
const item = list[i];
const n = String(item.index).padStart(paddedLen, '0');
console.log(`| ${n} | ${item.folderName} | ${item.fileName} |`);
}
// console.log('let list = ', list, ';');
} catch (err) {
throw new Error(err);
}
}
const folderPath = '../../case';
readFolderContents(folderPath).catch(err => console.error(err));
Promise版本
代码
const fs = require('fs');
const path = require('path');
// 文件夹路径
// C:\mssj\web\web-case\case\nodeJs\index.js
// C:\mssj\web\web-case\case\nodeJs\index.html
// C:\mssj\web\web-case\case\ajaxProgressMonitoring\index.html
const folderPath = '../../case';
// 读取文件夹中的内容
fs.readdir(folderPath, (err, files) => {
if (err) throw new Error(JSON.stringify(err));
// 过滤出文件夹
let subfolders = files.filter(file => fs.statSync(path.join(folderPath, file)).isDirectory());
let len = subfolders.length;
let list = [];
len = String(len).length;
len = Number(len);
// 创建一个 Promise 数组,用于保存每个读取文件的 Promise
let promises = subfolders.map((_FN, i) => {
const filePath = path.join(folderPath, _FN, 'index.html');
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) return reject(err);
const titleRegex = /<title>(.*?)<\/title>/gi;
const matches = titleRegex.exec(data);
if (matches && matches.length > 1) {
const title = matches[1];
const n = i + 1;
const obj = {};
obj.id = `id_${n}`;
obj.index = n;
obj.folderName = _FN;
obj.fileName = title;
list.push({ ...obj });
resolve();
} else {
reject(new Error('Title tag not found in the HTML file.'));
}
});
});
});
// 等待所有 Promise 完成
Promise.all(promises)
.then(() => {
list = list.sort((a, b) => a.index - b.index);
for (let i = 0; i < list.length; i++) {
const item = list[i];
const n = String(item.index).padStart(len, '0');
console.log(`| ${n} | ${item.folderName} | ${item.fileName} |`);
}
})
.catch(err => {
throw new Error(JSON.stringify(err));
});
});
解析
这是一段Node.js脚本代码,用于读取指定文件夹中的HTML文件,并提取每个HTML文件中的标题信息。然后按照文件夹中文件的顺序输出标题信息。
01、引入Node.js的核心模块fs(文件系统)和path(路径处理)。
const fs = require('fs'); const path = require('path');
02、定义要读取的文件夹路径。
const folderPath = '../../case';
03、使用fs.readdir方法读取文件夹中的内容,获取文件夹中的所有文件和文件夹。
fs.readdir(folderPath, (err, files) => { if (err) throw new Error(JSON.stringify(err));
04、过滤出文件夹中的子文件夹。
let subfolders = files.filter(file => fs.statSync(path.join(folderPath, file)).isDirectory());
05、初始化一个空数组list用于保存提取的标题信息。
let list = [];
06、使用map方法遍历子文件夹,并创建一个Promise数组,每个Promise对象用于读取子文件夹中的HTML文件。
let promises = subfolders.map((_FN, i) => { const filePath = path.join(folderPath, _FN, 'index.html'); return new Promise((resolve, reject) => { fs.readFile(filePath, 'utf8', (err, data) => { // 文件读取完成后的处理逻辑 }); }); });
07、在每个Promise对象的回调函数中,使用fs.readFile方法读取HTML文件,并提取标题信息。
const titleRegex = /<title>(.*?)<\/title>/gi; const matches = titleRegex.exec(data);
08、如果成功提取到标题信息,则将其存储在list数组中。
const title = matches[1]; const n = i + 1; const obj = {}; obj.id = `id_${n}`; obj.index = n; obj.folderName = _FN; obj.fileName = title; list.push({ ...obj }); resolve();
09、如果提取标题信息失败,则通过reject方法拒绝Promise,并抛出一个错误。
reject(new Error('Title tag not found in the HTML file.'));
10、使用Promise.all方法等待所有Promise对象完成,然后对list数组按照index属性排序,并输出每个HTML文件的标题信息。
Promise.all(promises) .then(() => { // 对list数组按照index属性排序 list = list.sort((a, b) => a.index - b.index); // 输出每个HTML文件的标题信息 for (let i = 0; i < list.length; i++) { const item = list[i]; const n = String(item.index).padStart(len, '0'); console.log(`| ${n} | ${item.folderName} | ${item.fileName} |`); } }) .catch(err => { throw new Error(JSON.stringify(err)); });
padStart
MDN
padStart()方法用另一个字符串填充当前字符串(如果需要会重复填充),直到达到给定的长度。填充是从当前字符串的开头开始的。
参数
padStart(targetLength) padStart(targetLength, padString)
targetLength: 当前str填充后的长度。如果该值小于或等于str.length,则会直接返回当前str。
padString: 用于填充当前str的字符串。如果padString太长,无法适应targetLength,则会从末尾被截断。默认值为Unicode“空格”字符(U+0020)。
返回值
在开头填充padString直到达到给定的targetLength所形成的String。