文件系统操作
文件系统概述
文件系统是操作系统用来管理和存储文件的一种机制。在Node.js中,我们可以通过fs模块来访问和操作文件系统。fs模块提供了丰富的API,允许我们进行文件的创建、读取、写入、删除等操作。
fs模块的引入
使用fs模块之前,需要先引入它:
const fs = require('fs');
同步和异步操作
Node.js的fs模块提供了同步和异步两种操作方式:
- 同步操作:阻塞代码执行,直到操作完成
- 异步操作:不阻塞代码执行,通过回调函数处理结果
注意:在实际应用中,推荐使用异步操作,以避免阻塞主线程。只有在某些特殊情况下,如脚本初始化时,才考虑使用同步操作。
文件读取
异步读取文件
fs.readFile('example.txt', 'utf8', (err, data) => {
if (err) {
console.error('读取文件失败:', err);
return;
}
console.log('文件内容:', data);
});
同步读取文件
try {
const data = fs.readFileSync('example.txt', 'utf8');
console.log('文件内容:', data);
} catch (err) {
console.error('读取文件失败:', err);
}
流式读取文件
对于大文件,可以使用流式读取,以避免一次性将文件加载到内存中。
const readStream = fs.createReadStream('large-file.txt', 'utf8');
readStream.on('data', (chunk) => {
console.log('读取到数据块:', chunk);
});
readStream.on('end', () => {
console.log('文件读取完成');
});
readStream.on('error', (err) => {
console.error('读取文件错误:', err);
});
文件写入
异步写入文件
const content = '这是要写入的内容';
fs.writeFile('example.txt', content, 'utf8', (err) => {
if (err) {
console.error('写入文件失败:', err);
return;
}
console.log('文件写入成功');
});
同步写入文件
try {
const content = '这是要写入的内容';
fs.writeFileSync('example.txt', content, 'utf8');
console.log('文件写入成功');
} catch (err) {
console.error('写入文件失败:', err);
}
追加写入
const content = '这是要追加的内容';
fs.appendFile('example.txt', content, 'utf8', (err) => {
if (err) {
console.error('追加内容失败:', err);
return;
}
console.log('内容追加成功');
});
流式写入文件
const writeStream = fs.createWriteStream('output.txt', 'utf8');
writeStream.write('第一行内容\n');
writeStream.write('第二行内容\n');
writeStream.end('结束内容\n');
writeStream.on('finish', () => {
console.log('文件写入完成');
});
writeStream.on('error', (err) => {
console.error('写入文件错误:', err);
});
文件和目录操作
检查文件是否存在
fs.access('example.txt', fs.constants.F_OK, (err) => {
console.log(err ? '文件不存在' : '文件存在');
});
获取文件信息
fs.stat('example.txt', (err, stats) => {
if (err) {
console.error('获取文件信息失败:', err);
return;
}
console.log('是否为文件:', stats.isFile());
console.log('是否为目录:', stats.isDirectory());
console.log('文件大小(字节):', stats.size);
console.log('创建时间:', stats.birthtime);
console.log('修改时间:', stats.mtime);
});
创建目录
fs.mkdir('new-directory', (err) => {
if (err) {
console.error('创建目录失败:', err);
return;
}
console.log('目录创建成功');
});
// 创建多级目录
fs.mkdir('parent/child/grandchild', { recursive: true }, (err) => {
if (err) {
console.error('创建多级目录失败:', err);
return;
}
console.log('多级目录创建成功');
});
读取目录内容
fs.readdir('.', (err, files) => {
if (err) {
console.error('读取目录失败:', err);
return;
}
console.log('目录内容:', files);
});
删除文件
fs.unlink('example.txt', (err) => {
if (err) {
console.error('删除文件失败:', err);
return;
}
console.log('文件删除成功');
});
删除目录
fs.rmdir('empty-directory', (err) => {
if (err) {
console.error('删除目录失败:', err);
return;
}
console.log('目录删除成功');
});
// 删除非空目录
fs.rmdir('non-empty-directory', { recursive: true }, (err) => {
if (err) {
console.error('删除非空目录失败:', err);
return;
}
console.log('非空目录删除成功');
});
重命名文件或目录
fs.rename('old-name.txt', 'new-name.txt', (err) => {
if (err) {
console.error('重命名失败:', err);
return;
}
console.log('文件重命名成功');
});
文件权限
在Unix/Linux系统中,文件权限是一个重要的概念。fs模块提供了修改文件权限的方法。
// 设置文件权限,0o644表示所有者可读写,组用户和其他用户可读
fs.chmod('example.txt', 0o644, (err) => {
if (err) {
console.error('修改文件权限失败:', err);
return;
}
console.log('文件权限修改成功');
});
路径处理
在进行文件系统操作时,通常需要处理文件路径。Node.js提供了path模块来帮助我们处理路径。
const path = require('path');
// 获取文件扩展名
const ext = path.extname('example.txt'); // 输出: '.txt'
// 获取文件名(不含扩展名)
const baseName = path.basename('example.txt', path.extname('example.txt')); // 输出: 'example'
// 连接路径
const fullPath = path.join(__dirname, 'folder', 'example.txt');
// 将相对路径转换为绝对路径
const absolutePath = path.resolve('folder', 'example.txt');
实用示例
复制文件
const fs = require('fs');
const path = require('path');
function copyFile(sourcePath, targetPath) {
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(sourcePath);
const writeStream = fs.createWriteStream(targetPath);
readStream.on('error', reject);
writeStream.on('error', reject);
writeStream.on('finish', resolve);
readStream.pipe(writeStream);
});
}
// 使用示例
copyFile('source.txt', 'destination.txt')
.then(() => console.log('文件复制成功'))
.catch(err => console.error('文件复制失败:', err));
读取目录下所有文件
const fs = require('fs');
const path = require('path');
function readAllFiles(dir) {
const files = fs.readdirSync(dir);
const results = [];
files.forEach(file => {
const filePath = path.join(dir, file);
const stats = fs.statSync(filePath);
if (stats.isFile()) {
results.push(filePath);
} else if (stats.isDirectory()) {
results.push(...readAllFiles(filePath));
}
});
return results;
}
// 使用示例
const allFiles = readAllFiles('.');
console.log('所有文件:', allFiles);
最佳实践
- 优先使用异步API,避免阻塞主线程
- 始终处理回调函数中的错误
- 使用流式API处理大文件
- 使用
path模块处理文件路径,确保跨平台兼容性 - 注意文件权限问题,特别是在Unix/Linux系统上
- 在操作文件前,检查文件或目录是否存在
- 对于复杂的文件操作,可以考虑使用第三方库,如
fs-extra,它提供了更多便捷的方法