Search K
Appearance
Appearance
📊 SEO元描述:2024年最新Node.js文件系统教程,详解fs模块同步异步操作、文件读写、目录操作、文件流处理、监听文件变化。包含完整代码示例,适合Node.js开发者掌握文件系统核心技能。
核心关键词:Node.js文件系统、fs模块、文件读写、目录操作、文件流、异步文件操作、Node.js文件处理
长尾关键词:Node.js怎么读写文件、fs模块同步异步区别、Node.js目录操作、文件流处理技巧、监听文件变化方法
通过本节Node.js文件系统模块详解的学习,你将系统性掌握:
什么时候使用同步操作,什么时候使用异步操作?这是Node.js文件系统操作中的核心问题。同步操作简单直接但会阻塞事件循环,异步操作不阻塞但需要处理回调。理解两者的性能影响和适用场景是高效文件处理的关键。
💡 选择原则:应用启动时可以使用同步操作加载配置,运行时处理用户请求必须使用异步操作。
// 🎉 fs模块同步异步操作完整对比
const fs = require('fs');
const fsPromises = require('fs').promises;
const path = require('path');
// === 同步操作示例 ===
class SyncFileOperations {
// 同步读取配置文件(适合应用启动时)
static loadConfigSync() {
console.log('=== 同步文件操作演示 ===');
try {
console.log('开始同步读取配置文件...');
const startTime = Date.now();
// 同步读取文件
const configData = fs.readFileSync('package.json', 'utf8');
const config = JSON.parse(configData);
const endTime = Date.now();
console.log(`✅ 同步读取完成,耗时: ${endTime - startTime}ms`);
return {
name: config.name,
version: config.version,
loadTime: endTime - startTime
};
} catch (error) {
console.error('❌ 同步读取失败:', error.message);
throw error;
}
}
// 同步文件操作的问题演示
static demonstrateBlockingIssue() {
console.log('\n=== 同步操作阻塞问题演示 ===');
// 启动一个定时器观察阻塞
const timer = setInterval(() => {
console.log('⏰ 定时器执行:', new Date().toLocaleTimeString());
}, 100);
console.log('开始同步操作...');
try {
// 模拟大文件读取(会阻塞)
for (let i = 0; i < 5; i++) {
const data = fs.readFileSync('package.json', 'utf8');
// 模拟处理时间
const start = Date.now();
while (Date.now() - start < 200) {
// 忙等待,模拟CPU密集操作
}
console.log(`同步操作 ${i + 1} 完成`);
}
} catch (error) {
console.error('同步操作失败:', error.message);
}
console.log('同步操作全部完成');
// 清理定时器
setTimeout(() => {
clearInterval(timer);
console.log('注意:在同步操作期间,定时器被阻塞了');
}, 1000);
}
// 同步目录操作
static syncDirectoryOperations() {
console.log('\n=== 同步目录操作 ===');
const testDir = './test-sync-dir';
try {
// 创建目录
if (!fs.existsSync(testDir)) {
fs.mkdirSync(testDir, { recursive: true });
console.log('✅ 同步创建目录成功');
}
// 写入测试文件
const testFiles = ['file1.txt', 'file2.txt', 'file3.txt'];
testFiles.forEach((filename, index) => {
const filePath = path.join(testDir, filename);
const content = `这是测试文件 ${index + 1}\n创建时间: ${new Date().toISOString()}`;
fs.writeFileSync(filePath, content, 'utf8');
console.log(`✅ 创建文件: ${filename}`);
});
// 读取目录内容
const files = fs.readdirSync(testDir);
console.log('目录内容:', files);
// 获取文件信息
files.forEach(filename => {
const filePath = path.join(testDir, filename);
const stats = fs.statSync(filePath);
console.log(`📄 ${filename}: ${stats.size} bytes, 修改时间: ${stats.mtime.toISOString()}`);
});
return { directory: testDir, files: files.length };
} catch (error) {
console.error('❌ 同步目录操作失败:', error.message);
throw error;
}
}
}
// === 异步操作示例 ===
class AsyncFileOperations {
// 异步读取文件(回调方式)
static loadConfigAsync(callback) {
console.log('\n=== 异步文件操作演示(回调) ===');
console.log('开始异步读取配置文件...');
const startTime = Date.now();
fs.readFile('package.json', 'utf8', (error, data) => {
if (error) {
console.error('❌ 异步读取失败:', error.message);
callback(error, null);
return;
}
try {
const config = JSON.parse(data);
const endTime = Date.now();
console.log(`✅ 异步读取完成,耗时: ${endTime - startTime}ms`);
const result = {
name: config.name,
version: config.version,
loadTime: endTime - startTime
};
callback(null, result);
} catch (parseError) {
console.error('❌ JSON解析失败:', parseError.message);
callback(parseError, null);
}
});
console.log('异步读取请求已发出,继续执行其他代码...');
}
// 异步操作不阻塞演示
static demonstrateNonBlocking() {
console.log('\n=== 异步操作非阻塞演示 ===');
// 启动定时器观察非阻塞特性
const timer = setInterval(() => {
console.log('⏰ 定时器执行:', new Date().toLocaleTimeString());
}, 100);
console.log('开始异步操作...');
// 并行执行多个异步文件操作
for (let i = 0; i < 5; i++) {
fs.readFile('package.json', 'utf8', (error, data) => {
if (error) {
console.error(`异步操作 ${i + 1} 失败:`, error.message);
return;
}
// 模拟处理时间
setTimeout(() => {
console.log(`✅ 异步操作 ${i + 1} 完成`);
}, Math.random() * 200);
});
}
console.log('所有异步操作已启动,主线程继续执行...');
// 清理定时器
setTimeout(() => {
clearInterval(timer);
console.log('注意:异步操作期间,定时器正常执行,没有被阻塞');
}, 2000);
}
// 异步目录操作
static asyncDirectoryOperations(callback) {
console.log('\n=== 异步目录操作 ===');
const testDir = './test-async-dir';
// 检查目录是否存在
fs.access(testDir, fs.constants.F_OK, (accessError) => {
if (accessError) {
// 目录不存在,创建目录
fs.mkdir(testDir, { recursive: true }, (mkdirError) => {
if (mkdirError) {
console.error('❌ 创建目录失败:', mkdirError.message);
callback(mkdirError, null);
return;
}
console.log('✅ 异步创建目录成功');
this.createTestFiles(testDir, callback);
});
} else {
console.log('目录已存在');
this.createTestFiles(testDir, callback);
}
});
}
static createTestFiles(testDir, callback) {
const testFiles = ['async1.txt', 'async2.txt', 'async3.txt'];
let completedFiles = 0;
const results = [];
testFiles.forEach((filename, index) => {
const filePath = path.join(testDir, filename);
const content = `这是异步测试文件 ${index + 1}\n创建时间: ${new Date().toISOString()}`;
fs.writeFile(filePath, content, 'utf8', (writeError) => {
if (writeError) {
console.error(`❌ 创建文件 ${filename} 失败:`, writeError.message);
results.push({ filename, error: writeError.message });
} else {
console.log(`✅ 创建文件: ${filename}`);
results.push({ filename, success: true });
}
completedFiles++;
if (completedFiles === testFiles.length) {
// 所有文件创建完成,读取目录内容
fs.readdir(testDir, (readdirError, files) => {
if (readdirError) {
console.error('❌ 读取目录失败:', readdirError.message);
callback(readdirError, null);
return;
}
console.log('异步目录内容:', files);
callback(null, { directory: testDir, files: files.length, results });
});
}
});
});
}
}
// === Promise版本异步操作 ===
class PromiseFileOperations {
// Promise版本文件操作
static async loadConfigPromise() {
console.log('\n=== Promise版本文件操作演示 ===');
try {
console.log('开始Promise读取配置文件...');
const startTime = Date.now();
const data = await fsPromises.readFile('package.json', 'utf8');
const config = JSON.parse(data);
const endTime = Date.now();
console.log(`✅ Promise读取完成,耗时: ${endTime - startTime}ms`);
return {
name: config.name,
version: config.version,
loadTime: endTime - startTime
};
} catch (error) {
console.error('❌ Promise读取失败:', error.message);
throw error;
}
}
// 并行Promise操作
static async parallelPromiseOperations() {
console.log('\n=== 并行Promise操作演示 ===');
try {
const startTime = Date.now();
// 并行读取多个文件
const [packageData, readmeData] = await Promise.all([
fsPromises.readFile('package.json', 'utf8').catch(err => ({ error: err.message })),
fsPromises.readFile('README.md', 'utf8').catch(err => ({ error: err.message }))
]);
const endTime = Date.now();
console.log(`✅ 并行读取完成,耗时: ${endTime - startTime}ms`);
return {
package: typeof packageData === 'string' ? JSON.parse(packageData) : packageData,
readme: typeof readmeData === 'string' ? { size: readmeData.length } : readmeData,
totalTime: endTime - startTime
};
} catch (error) {
console.error('❌ 并行Promise操作失败:', error.message);
throw error;
}
}
// Promise目录操作
static async promiseDirectoryOperations() {
console.log('\n=== Promise目录操作演示 ===');
const testDir = './test-promise-dir';
try {
// 确保目录存在
await fsPromises.mkdir(testDir, { recursive: true });
console.log('✅ Promise创建目录成功');
// 并行创建多个文件
const testFiles = ['promise1.txt', 'promise2.txt', 'promise3.txt'];
const filePromises = testFiles.map((filename, index) => {
const filePath = path.join(testDir, filename);
const content = `这是Promise测试文件 ${index + 1}\n创建时间: ${new Date().toISOString()}`;
return fsPromises.writeFile(filePath, content, 'utf8');
});
await Promise.all(filePromises);
console.log('✅ 所有文件创建完成');
// 读取目录内容
const files = await fsPromises.readdir(testDir);
console.log('Promise目录内容:', files);
// 获取文件详细信息
const fileStats = await Promise.all(
files.map(async (filename) => {
const filePath = path.join(testDir, filename);
const stats = await fsPromises.stat(filePath);
return {
name: filename,
size: stats.size,
modified: stats.mtime.toISOString(),
isFile: stats.isFile()
};
})
);
console.log('文件详细信息:', fileStats);
return {
directory: testDir,
files: files.length,
details: fileStats
};
} catch (error) {
console.error('❌ Promise目录操作失败:', error.message);
throw error;
}
}
}
// === 性能对比测试 ===
class PerformanceComparison {
static async comparePerformance() {
console.log('\n=== 文件操作性能对比 ===');
const iterations = 10;
const testFile = 'package.json';
// 同步操作性能测试
console.log('🔄 测试同步操作性能...');
const syncStartTime = Date.now();
for (let i = 0; i < iterations; i++) {
try {
fs.readFileSync(testFile, 'utf8');
} catch (error) {
console.error(`同步操作 ${i + 1} 失败:`, error.message);
}
}
const syncEndTime = Date.now();
const syncDuration = syncEndTime - syncStartTime;
// 异步操作性能测试
console.log('🔄 测试异步操作性能...');
const asyncStartTime = Date.now();
const asyncPromises = [];
for (let i = 0; i < iterations; i++) {
asyncPromises.push(
fsPromises.readFile(testFile, 'utf8').catch(error => {
console.error(`异步操作 ${i + 1} 失败:`, error.message);
return null;
})
);
}
await Promise.all(asyncPromises);
const asyncEndTime = Date.now();
const asyncDuration = asyncEndTime - asyncStartTime;
// 结果对比
const comparison = {
iterations,
sync: {
duration: syncDuration,
averagePerOperation: (syncDuration / iterations).toFixed(2),
blocking: true
},
async: {
duration: asyncDuration,
averagePerOperation: (asyncDuration / iterations).toFixed(2),
blocking: false
},
speedup: (syncDuration / asyncDuration).toFixed(2)
};
console.log('\n📊 性能对比结果:');
console.log(JSON.stringify(comparison, null, 2));
return comparison;
}
}
// 运行演示
(async () => {
try {
// 同步操作演示
const syncConfig = SyncFileOperations.loadConfigSync();
console.log('同步配置结果:', syncConfig);
SyncFileOperations.demonstrateBlockingIssue();
setTimeout(async () => {
const syncDirResult = SyncFileOperations.syncDirectoryOperations();
console.log('同步目录操作结果:', syncDirResult);
// 异步操作演示
AsyncFileOperations.loadConfigAsync((error, result) => {
if (error) {
console.error('异步配置加载失败:', error.message);
} else {
console.log('异步配置结果:', result);
}
});
AsyncFileOperations.demonstrateNonBlocking();
AsyncFileOperations.asyncDirectoryOperations((error, result) => {
if (error) {
console.error('异步目录操作失败:', error.message);
} else {
console.log('异步目录操作结果:', result);
}
});
// Promise操作演示
const promiseConfig = await PromiseFileOperations.loadConfigPromise();
console.log('Promise配置结果:', promiseConfig);
const parallelResult = await PromiseFileOperations.parallelPromiseOperations();
console.log('并行Promise结果:', parallelResult);
const promiseDirResult = await PromiseFileOperations.promiseDirectoryOperations();
console.log('Promise目录操作结果:', promiseDirResult);
// 性能对比
const performanceResult = await PerformanceComparison.comparePerformance();
console.log('性能对比完成');
}, 3000);
} catch (error) {
console.error('演示执行失败:', error.message);
}
})();
// 导出模块
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
SyncFileOperations,
AsyncFileOperations,
PromiseFileOperations,
PerformanceComparison
};
}文件读写是文件系统操作的核心,需要掌握不同的读写方式和编码处理。
// 🎉 文件读写操作完整示例
const fs = require('fs');
const fsPromises = require('fs').promises;
const path = require('path');
// === 高级文件读写操作 ===
class AdvancedFileOperations {
constructor(basePath = './') {
this.basePath = basePath;
}
// 安全文件读取(带重试机制)
async safeReadFile(filename, options = {}) {
const {
encoding = 'utf8',
maxRetries = 3,
retryDelay = 1000,
timeout = 5000
} = options;
const filePath = path.resolve(this.basePath, filename);
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`📖 尝试读取文件 (第${attempt}次): ${filename}`);
// 设置超时
const readPromise = fsPromises.readFile(filePath, encoding);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('读取超时')), timeout);
});
const data = await Promise.race([readPromise, timeoutPromise]);
console.log(`✅ 文件读取成功: ${filename}`);
return {
success: true,
data,
size: Buffer.byteLength(data, encoding),
attempts: attempt
};
} catch (error) {
console.error(`❌ 第${attempt}次读取失败:`, error.message);
if (attempt === maxRetries) {
throw new Error(`文件读取失败,已重试${maxRetries}次: ${error.message}`);
}
// 等待后重试
await new Promise(resolve => setTimeout(resolve, retryDelay));
retryDelay *= 2; // 指数退避
}
}
}
// 安全文件写入(原子操作)
async safeWriteFile(filename, data, options = {}) {
const {
encoding = 'utf8',
backup = true,
atomic = true
} = options;
const filePath = path.resolve(this.basePath, filename);
const tempPath = filePath + '.tmp';
const backupPath = filePath + '.backup';
try {
// 创建备份
if (backup) {
try {
await fsPromises.access(filePath);
await fsPromises.copyFile(filePath, backupPath);
console.log(`📋 创建备份: ${filename}.backup`);
} catch (error) {
// 原文件不存在,无需备份
}
}
if (atomic) {
// 原子写入:先写临时文件,再重命名
await fsPromises.writeFile(tempPath, data, encoding);
await fsPromises.rename(tempPath, filePath);
console.log(`✅ 原子写入完成: ${filename}`);
} else {
// 直接写入
await fsPromises.writeFile(filePath, data, encoding);
console.log(`✅ 直接写入完成: ${filename}`);
}
return {
success: true,
size: Buffer.byteLength(data, encoding),
atomic,
backup
};
} catch (error) {
// 清理临时文件
try {
await fsPromises.unlink(tempPath);
} catch (cleanupError) {
// 忽略清理错误
}
console.error(`❌ 文件写入失败: ${filename}`, error.message);
throw error;
}
}
// 文件追加操作
async appendToFile(filename, data, options = {}) {
const {
encoding = 'utf8',
separator = '\n',
maxSize = 10 * 1024 * 1024 // 10MB
} = options;
const filePath = path.resolve(this.basePath, filename);
try {
// 检查文件大小
try {
const stats = await fsPromises.stat(filePath);
if (stats.size > maxSize) {
throw new Error(`文件过大 (${stats.size} bytes),超过限制 (${maxSize} bytes)`);
}
} catch (statError) {
if (statError.code !== 'ENOENT') {
throw statError;
}
// 文件不存在,继续执行
}
const appendData = separator + data;
await fsPromises.appendFile(filePath, appendData, encoding);
console.log(`✅ 数据追加成功: ${filename}`);
return {
success: true,
appendedSize: Buffer.byteLength(appendData, encoding)
};
} catch (error) {
console.error(`❌ 数据追加失败: ${filename}`, error.message);
throw error;
}
}
// 分块读取大文件
async readFileInChunks(filename, options = {}) {
const {
chunkSize = 64 * 1024, // 64KB
encoding = 'utf8',
onChunk = null
} = options;
const filePath = path.resolve(this.basePath, filename);
try {
const stats = await fsPromises.stat(filePath);
const fileSize = stats.size;
const chunks = [];
console.log(`📖 开始分块读取文件: ${filename} (${fileSize} bytes)`);
const fileHandle = await fsPromises.open(filePath, 'r');
try {
let position = 0;
let chunkIndex = 0;
while (position < fileSize) {
const remainingBytes = fileSize - position;
const currentChunkSize = Math.min(chunkSize, remainingBytes);
const buffer = Buffer.alloc(currentChunkSize);
const { bytesRead } = await fileHandle.read(buffer, 0, currentChunkSize, position);
const chunkData = buffer.slice(0, bytesRead).toString(encoding);
chunks.push(chunkData);
if (onChunk) {
onChunk(chunkData, chunkIndex, position, fileSize);
}
position += bytesRead;
chunkIndex++;
console.log(`📄 读取块 ${chunkIndex}: ${bytesRead} bytes (${((position / fileSize) * 100).toFixed(1)}%)`);
}
console.log(`✅ 分块读取完成: ${chunkIndex} 个块`);
return {
success: true,
chunks,
totalChunks: chunkIndex,
totalSize: fileSize,
data: chunks.join('')
};
} finally {
await fileHandle.close();
}
} catch (error) {
console.error(`❌ 分块读取失败: ${filename}`, error.message);
throw error;
}
}
// 文件比较
async compareFiles(file1, file2, options = {}) {
const {
algorithm = 'md5',
chunkSize = 64 * 1024
} = options;
const crypto = require('crypto');
try {
console.log(`🔍 比较文件: ${file1} vs ${file2}`);
// 首先比较文件大小
const [stats1, stats2] = await Promise.all([
fsPromises.stat(path.resolve(this.basePath, file1)),
fsPromises.stat(path.resolve(this.basePath, file2))
]);
if (stats1.size !== stats2.size) {
return {
identical: false,
reason: 'size_different',
file1Size: stats1.size,
file2Size: stats2.size
};
}
// 计算文件哈希
const [hash1, hash2] = await Promise.all([
this.calculateFileHash(file1, algorithm),
this.calculateFileHash(file2, algorithm)
]);
const identical = hash1 === hash2;
console.log(`${identical ? '✅' : '❌'} 文件比较结果: ${identical ? '相同' : '不同'}`);
return {
identical,
reason: identical ? 'identical' : 'content_different',
file1Hash: hash1,
file2Hash: hash2,
algorithm,
size: stats1.size
};
} catch (error) {
console.error('❌ 文件比较失败:', error.message);
throw error;
}
}
// 计算文件哈希
async calculateFileHash(filename, algorithm = 'md5') {
const crypto = require('crypto');
const filePath = path.resolve(this.basePath, filename);
return new Promise((resolve, reject) => {
const hash = crypto.createHash(algorithm);
const stream = fs.createReadStream(filePath);
stream.on('data', (data) => {
hash.update(data);
});
stream.on('end', () => {
resolve(hash.digest('hex'));
});
stream.on('error', (error) => {
reject(error);
});
});
}
// 文件加密写入
async writeEncryptedFile(filename, data, password, options = {}) {
const crypto = require('crypto');
const {
algorithm = 'aes-256-gcm',
encoding = 'utf8'
} = options;
try {
// 生成密钥和IV
const key = crypto.scryptSync(password, 'salt', 32);
const iv = crypto.randomBytes(16);
// 创建加密器
const cipher = crypto.createCipher(algorithm, key);
// 加密数据
let encrypted = cipher.update(data, encoding, 'hex');
encrypted += cipher.final('hex');
// 保存加密数据和IV
const encryptedData = {
algorithm,
iv: iv.toString('hex'),
data: encrypted
};
await this.safeWriteFile(filename, JSON.stringify(encryptedData), { encoding: 'utf8' });
console.log(`🔐 加密文件写入成功: ${filename}`);
return {
success: true,
algorithm,
encryptedSize: encrypted.length
};
} catch (error) {
console.error(`❌ 加密文件写入失败: ${filename}`, error.message);
throw error;
}
}
// 文件解密读取
async readEncryptedFile(filename, password, options = {}) {
const crypto = require('crypto');
const { encoding = 'utf8' } = options;
try {
const encryptedContent = await this.safeReadFile(filename, { encoding: 'utf8' });
const encryptedData = JSON.parse(encryptedContent.data);
// 重建密钥
const key = crypto.scryptSync(password, 'salt', 32);
// 创建解密器
const decipher = crypto.createDecipher(encryptedData.algorithm, key);
// 解密数据
let decrypted = decipher.update(encryptedData.data, 'hex', encoding);
decrypted += decipher.final(encoding);
console.log(`🔓 加密文件读取成功: ${filename}`);
return {
success: true,
data: decrypted,
algorithm: encryptedData.algorithm
};
} catch (error) {
console.error(`❌ 加密文件读取失败: ${filename}`, error.message);
throw error;
}
}
}
// === JSON文件操作工具 ===
class JSONFileManager extends AdvancedFileOperations {
// 读取JSON文件
async readJSON(filename, options = {}) {
const { defaultValue = null, validate = null } = options;
try {
const result = await this.safeReadFile(filename);
const jsonData = JSON.parse(result.data);
if (validate && typeof validate === 'function') {
const isValid = validate(jsonData);
if (!isValid) {
throw new Error('JSON数据验证失败');
}
}
console.log(`✅ JSON文件读取成功: ${filename}`);
return jsonData;
} catch (error) {
if (error.code === 'ENOENT' && defaultValue !== null) {
console.log(`📄 文件不存在,返回默认值: ${filename}`);
return defaultValue;
}
console.error(`❌ JSON文件读取失败: ${filename}`, error.message);
throw error;
}
}
// 写入JSON文件
async writeJSON(filename, data, options = {}) {
const {
indent = 2,
validate = null,
backup = true
} = options;
try {
if (validate && typeof validate === 'function') {
const isValid = validate(data);
if (!isValid) {
throw new Error('JSON数据验证失败');
}
}
const jsonString = JSON.stringify(data, null, indent);
await this.safeWriteFile(filename, jsonString, { backup });
console.log(`✅ JSON文件写入成功: ${filename}`);
return {
success: true,
size: jsonString.length
};
} catch (error) {
console.error(`❌ JSON文件写入失败: ${filename}`, error.message);
throw error;
}
}
// 更新JSON文件
async updateJSON(filename, updater, options = {}) {
const { createIfNotExists = true, defaultValue = {} } = options;
try {
let currentData;
try {
currentData = await this.readJSON(filename);
} catch (error) {
if (error.code === 'ENOENT' && createIfNotExists) {
currentData = defaultValue;
} else {
throw error;
}
}
const updatedData = typeof updater === 'function'
? updater(currentData)
: { ...currentData, ...updater };
await this.writeJSON(filename, updatedData, options);
console.log(`✅ JSON文件更新成功: ${filename}`);
return updatedData;
} catch (error) {
console.error(`❌ JSON文件更新失败: ${filename}`, error.message);
throw error;
}
}
}
// 使用示例
(async () => {
try {
const fileOps = new AdvancedFileOperations('./test-files');
const jsonManager = new JSONFileManager('./test-files');
// 确保测试目录存在
await fsPromises.mkdir('./test-files', { recursive: true });
// 安全文件读写演示
await fileOps.safeWriteFile('test.txt', '这是测试内容\n第二行内容', { backup: true });
const readResult = await fileOps.safeReadFile('test.txt');
console.log('读取结果:', readResult);
// 文件追加演示
await fileOps.appendToFile('test.txt', '追加的内容');
// JSON文件操作演示
const testData = {
name: 'Node.js学习',
version: '1.0.0',
features: ['文件操作', 'JSON处理', '错误处理'],
config: {
debug: true,
maxRetries: 3
}
};
await jsonManager.writeJSON('config.json', testData);
const configData = await jsonManager.readJSON('config.json');
console.log('JSON配置:', configData);
// 更新JSON文件
await jsonManager.updateJSON('config.json', (data) => ({
...data,
lastUpdated: new Date().toISOString(),
config: {
...data.config,
debug: false
}
}));
console.log('高级文件操作演示完成');
} catch (error) {
console.error('演示执行失败:', error.message);
}
})();
// 导出模块
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
AdvancedFileOperations,
JSONFileManager
};
}通过本节Node.js文件系统模块详解的学习,你已经掌握:
A: 仅在应用启动时加载配置文件或初始化数据时使用同步操作。运行时处理用户请求必须使用异步操作,避免阻塞事件循环。
A: 使用Stream API或分块读取方式处理大文件。避免一次性将整个文件加载到内存中,这会导致内存溢出。
A: 始终使用try-catch包围文件操作,检查特定的错误代码(如ENOENT、EACCES),实现重试机制,并提供有意义的错误信息。
A: 使用临时文件写入然后重命名的方式实现原子操作,或者使用文件锁机制防止并发写入冲突。
A: 使用异步操作、合理设置缓冲区大小、批量处理文件操作、使用Stream处理大文件、避免频繁的小文件操作。
// 推荐的文件操作错误处理模式
async function robustFileOperation(filename) {
try {
const data = await fsPromises.readFile(filename, 'utf8');
return data;
} catch (error) {
switch (error.code) {
case 'ENOENT':
throw new Error(`文件不存在: ${filename}`);
case 'EACCES':
throw new Error(`权限不足: ${filename}`);
case 'EISDIR':
throw new Error(`路径是目录而非文件: ${filename}`);
default:
throw new Error(`文件操作失败: ${error.message}`);
}
}
}// 通用文件操作工具类
class FileUtils {
static async ensureDir(dirPath) {
try {
await fsPromises.mkdir(dirPath, { recursive: true });
} catch (error) {
if (error.code !== 'EEXIST') {
throw error;
}
}
}
static async copyFile(src, dest) {
await this.ensureDir(path.dirname(dest));
await fsPromises.copyFile(src, dest);
}
static async moveFile(src, dest) {
await this.copyFile(src, dest);
await fsPromises.unlink(src);
}
}"掌握Node.js文件系统操作是后端开发的基础技能。从简单的文件读写到复杂的流处理,每种技术都有其适用场景。理解同步异步操作的权衡,选择合适的文件处理方式,能够让你的Node.js应用更加高效和稳定。接下来,让我们学习目录操作和文件流处理的高级技巧!"