Skip to content

Commit 8c36ba5

Browse files
author
Taois
committed
feat: 文件头工具调优
1 parent 29b0d66 commit 8c36ba5

File tree

2 files changed

+108
-4
lines changed

2 files changed

+108
-4
lines changed

scripts/test/test_cctv_header.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,12 @@ async function runTest() {
2929

3030
// 2. 读取文件头
3131
console.log('\n[2/6] 正在读取文件头...');
32+
const startTime = performance.now();
3233
let header = await FileHeaderManager.readHeader(testFile);
34+
const endTime = performance.now();
35+
const duration = endTime - startTime;
36+
console.log(`⏱️ 读取耗时: ${duration.toFixed(4)} ms`);
37+
3338
if (header) {
3439
console.log('✅ 读取到的文件头:', JSON.stringify(header, null, 2));
3540
} else {
@@ -83,13 +88,89 @@ async function runTest() {
8388
throw new Error('Removal verification failed');
8489
}
8590

91+
// 7. 性能测试 (循环 10000 次)
92+
const iterations = 10000;
93+
console.log(`\n[7/10] 性能基准测试 (读取 ${iterations} 次取平均)...`);
94+
// 确保文件有头
95+
await fs.copyFile(sourceFile, testFile);
96+
97+
const perfStart = performance.now();
98+
for(let i=0; i<iterations; i++) {
99+
await FileHeaderManager.readHeader(testFile);
100+
}
101+
const perfEnd = performance.now();
102+
const totalTime = perfEnd - perfStart;
103+
const avgTime = totalTime / iterations;
104+
console.log(`总耗时: ${totalTime.toFixed(2)} ms`);
105+
console.log(`平均每次读取耗时: ${avgTime.toFixed(4)} ms`);
106+
console.log('✅ 性能测试完成。');
107+
108+
// 8. 优化后的 readHeader 性能测试
109+
console.log(`\n[8/10] 优化后的 readHeader (Partial Read) 性能测试 (读取 ${iterations} 次取平均)...`);
110+
111+
const perfStartOptimized = performance.now();
112+
for(let i=0; i<iterations; i++) {
113+
await FileHeaderManager.readHeader(testFile);
114+
}
115+
const perfEndOptimized = performance.now();
116+
const totalTimeOptimized = perfEndOptimized - perfStartOptimized;
117+
const avgTimeOptimized = totalTimeOptimized / iterations;
118+
119+
console.log(`总耗时 (Optimized): ${totalTimeOptimized.toFixed(2)} ms`);
120+
console.log(`平均每次读取耗时 (Optimized): ${avgTimeOptimized.toFixed(4)} ms`);
121+
122+
const finalImprovement = ((avgTime - avgTimeOptimized) / avgTime * 100).toFixed(2);
123+
console.log(`🚀 最终性能提升: ${finalImprovement}%`);
124+
125+
// 9. 写文件头性能测试
126+
console.log(`\n[9/10] 写文件头性能测试 (循环 ${iterations} 次)...`);
127+
// 注意:写文件涉及磁盘IO,次数不宜过多,且每次都会修改文件
128+
// 预热:确保 header 对象存在
129+
const headerForWrite = await FileHeaderManager.readHeader(testFile) || {};
130+
headerForWrite.perf_test = true;
131+
132+
const perfStartWrite = performance.now();
133+
for(let i=0; i<iterations; i++) {
134+
headerForWrite.perf_counter = i;
135+
// 禁用备份以测试纯粹的写入性能,避免大量备份文件
136+
await FileHeaderManager.writeHeader(testFile, headerForWrite, { createBackup: false });
137+
}
138+
const perfEndWrite = performance.now();
139+
const totalTimeWrite = perfEndWrite - perfStartWrite;
140+
const avgTimeWrite = totalTimeWrite / iterations;
141+
console.log(`总耗时 (Write ${iterations}次): ${totalTimeWrite.toFixed(2)} ms`);
142+
console.log(`平均每次写入耗时: ${avgTimeWrite.toFixed(4)} ms`);
143+
144+
// 10. 移除文件头性能测试
145+
console.log(`\n[10/10] 移除文件头性能测试 (循环 ${iterations} 次)...`);
146+
// 注意:removeHeader 主要是内存操作(如果传入的是内容),或者 读+内存操作(如果传入的是路径)
147+
// 这里测试传入路径的情况,包含读取文件
148+
149+
// 先确保文件有头
150+
await FileHeaderManager.writeHeader(testFile, headerForWrite, { createBackup: false });
151+
152+
const perfStartRemove = performance.now();
153+
for(let i=0; i<iterations; i++) {
154+
// 每次循环前需要重置文件状态吗?
155+
// removeHeader 返回的是字符串,不写回文件。所以这里测试的是 "读取+正则处理" 的性能。
156+
// 这是一个纯计算 + 读取的测试,不会修改磁盘文件。
157+
await FileHeaderManager.removeHeader(testFile);
158+
}
159+
const perfEndRemove = performance.now();
160+
const totalTimeRemove = perfEndRemove - perfStartRemove;
161+
const avgTimeRemove = totalTimeRemove / iterations;
162+
console.log(`总耗时 (Remove ${iterations}次): ${totalTimeRemove.toFixed(2)} ms`);
163+
console.log(`平均每次移除耗时 (计算): ${avgTimeRemove.toFixed(4)} ms`);
164+
165+
86166
console.log('\n=== 测试全部通过 ===');
87167

88168
} catch (error) {
89169
console.error('\n❌ 测试过程中发生错误:', error);
90170
} finally {
91-
// 7. 清理
92-
console.log('\n[7/7] 清理测试文件...');
171+
// 8. 清理
172+
console.log('\n[8/8] 清理测试文件...');
173+
93174
try {
94175
await fs.unlink(testFile);
95176
console.log('✅ 测试文件已删除。');

utils/fileHeaderManager.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,16 +136,39 @@ class FileHeaderManager {
136136
/**
137137
* 读取文件头信息
138138
* @param {string} filePath 文件路径
139+
* @param {Object} [options] 配置选项
140+
* @param {number} [options.maxHeaderSize=8192] 最大读取字节数 (默认 8KB)
139141
* @returns {Object|null} 头信息对象
140142
*/
141-
static async readHeader(filePath) {
142-
const content = await fs.readFile(filePath, 'utf8');
143+
static async readHeader(filePath, options = {}) {
144+
const { maxHeaderSize = 8192 } = options;
143145
const ext = path.extname(filePath);
144146
const config = this.COMMENT_CONFIG[ext];
145147

146148
if (!config) throw new Error(`Unsupported file type: ${ext}`);
147149

150+
let content = '';
151+
let handle;
152+
153+
try {
154+
// 使用 fs.open 和 read 读取部分内容,提高性能
155+
handle = await fs.open(filePath, 'r');
156+
const buffer = Buffer.alloc(maxHeaderSize);
157+
const { bytesRead } = await handle.read(buffer, 0, maxHeaderSize, 0);
158+
content = buffer.toString('utf8', 0, bytesRead);
159+
} catch (error) {
160+
// 如果读取失败 (如文件不存在),抛出错误或返回 null
161+
if (handle) await handle.close();
162+
throw error;
163+
} finally {
164+
if (handle) await handle.close();
165+
}
166+
148167
const match = content.match(config.regex);
168+
169+
// 如果在头部没有找到匹配项,且文件可能很大,也许是注释太长被截断了?
170+
// 但目前假设 header 应该在 8KB 内。如果需要完整性,可以考虑 fallback 到读取整个文件,
171+
// 但为了性能,这里仅依赖前 8KB。
149172
if (!match) return null;
150173

151174
const headerBlock = this.findHeaderBlock(match[0], ext);

0 commit comments

Comments
 (0)