Node.js 文件系统操作详解
fs 模块
javascript
const fs = require('fs');
const fsPromises = require('fs').promises;文件读取
同步:
javascript
try {
const data = fs.readFileSync('file.txt', 'utf8');
} catch (err) {
console.error(err);
}异步回调:
javascript
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) return console.error(err);
console.log(data);
});Promise:
javascript
const data = await fsPromises.readFile('file.txt', 'utf8');读取二进制文件
javascript
const image = fs.readFileSync('image.png');
// image 是 Buffer 对象
console.log(image.length); // 文件大小(字节)文件写入
同步写入
javascript
try {
fs.writeFileSync('output.txt', 'Hello, Node.js!', 'utf8');
console.log('文件写入成功');
} catch (err) {
console.error('写入文件失败:', err);
}异步写入
javascript
// 回调方式
fs.writeFile('output.txt', 'Hello, Node.js!', 'utf8', (err) => {
if (err) {
console.error('写入文件失败:', err);
return;
}
console.log('文件写入成功');
});
// Promise 方式
async function writeFile() {
try {
await fsPromises.writeFile('output.txt', 'Hello, Node.js!', 'utf8');
console.log('文件写入成功');
} catch (err) {
console.error('写入文件失败:', err);
}
}追加写入
javascript
// 追加内容到文件末尾
fs.appendFile('log.txt', '新日志条目\n', 'utf8', (err) => {
if (err) console.error(err);
});
// 同步方式
fs.appendFileSync('log.txt', '新日志条目\n', 'utf8');文件信息
检查文件是否存在
javascript
// 同步方式
if (fs.existsSync('file.txt')) {
console.log('文件存在');
}
// 异步方式(已废弃,不推荐)
// 推荐使用 fs.access 或 fsPromises.access获取文件信息
javascript
// 同步方式
const stats = fs.statSync('file.txt');
console.log('文件大小:', stats.size);
console.log('创建时间:', stats.birthtime);
console.log('修改时间:', stats.mtime);
console.log('是文件:', stats.isFile());
console.log('是目录:', stats.isDirectory());
// 异步方式
fs.stat('file.txt', (err, stats) => {
if (err) {
console.error(err);
return;
}
console.log('文件信息:', stats);
});检查访问权限
javascript
// 检查文件是否可读
fs.access('file.txt', fs.constants.R_OK, (err) => {
if (err) {
console.log('文件不可读');
} else {
console.log('文件可读');
}
});
// 检查多个权限
fs.access('file.txt', fs.constants.R_OK | fs.constants.W_OK, (err) => {
if (err) {
console.log('文件不可读写');
} else {
console.log('文件可读写');
}
});目录操作
创建目录
javascript
// 同步创建
fs.mkdirSync('new-directory');
// 异步创建
fs.mkdir('new-directory', (err) => {
if (err) {
console.error(err);
return;
}
console.log('目录创建成功');
});
// 递归创建(Node.js 10+)
fs.mkdir('path/to/directory', { recursive: true }, (err) => {
if (err) console.error(err);
});读取目录
javascript
// 同步读取
const files = fs.readdirSync('.');
console.log('文件列表:', files);
// 异步读取
fs.readdir('.', (err, files) => {
if (err) {
console.error(err);
return;
}
console.log('文件列表:', files);
});
// 读取详细信息
fs.readdir('.', { withFileTypes: true }, (err, entries) => {
if (err) {
console.error(err);
return;
}
entries.forEach(entry => {
if (entry.isDirectory()) {
console.log(`目录: ${entry.name}`);
} else {
console.log(`文件: ${entry.name}`);
}
});
});删除目录
javascript
// 删除空目录
fs.rmdir('directory', (err) => {
if (err) console.error(err);
});
// 递归删除(Node.js 14.14+)
fs.rm('directory', { recursive: true }, (err) => {
if (err) console.error(err);
});文件操作
重命名/移动文件
javascript
// 重命名
fs.rename('old-name.txt', 'new-name.txt', (err) => {
if (err) console.error(err);
});
// 移动文件
fs.rename('file.txt', 'directory/file.txt', (err) => {
if (err) console.error(err);
});复制文件
javascript
// 使用 fs.copyFile(Node.js 8.5+)
fs.copyFile('source.txt', 'destination.txt', (err) => {
if (err) console.error(err);
});
// 使用流复制大文件
const fs = require('fs');
const readStream = fs.createReadStream('large-file.txt');
const writeStream = fs.createWriteStream('copy.txt');
readStream.pipe(writeStream);
readStream.on('end', () => {
console.log('复制完成');
});删除文件
javascript
fs.unlink('file.txt', (err) => {
if (err) console.error(err);
console.log('文件删除成功');
});流处理
可读流
javascript
const readStream = fs.createReadStream('large-file.txt', {
encoding: 'utf8',
highWaterMark: 64 * 1024 // 64KB 缓冲区
});
readStream.on('data', (chunk) => {
console.log('读取数据块,大小:', chunk.length);
// 处理数据块
});
readStream.on('end', () => {
console.log('读取完成');
});
readStream.on('error', (err) => {
console.error('读取错误:', err);
});可写流
javascript
const writeStream = fs.createWriteStream('output.txt', {
encoding: 'utf8',
flags: 'a' // 追加模式
});
writeStream.write('第一行数据\n');
writeStream.write('第二行数据\n');
writeStream.end('最后一行数据');
writeStream.on('finish', () => {
console.log('写入完成');
});
writeStream.on('error', (err) => {
console.error('写入错误:', err);
});管道操作
javascript
// 基本管道
const readStream = fs.createReadStream('input.txt');
const writeStream = fs.createWriteStream('output.txt');
readStream.pipe(writeStream);
// 链式管道
const zlib = require('zlib');
readStream
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('output.txt.gz'));监听文件变化
watchFile
javascript
fs.watchFile('file.txt', (curr, prev) => {
console.log('文件已修改');
console.log('当前大小:', curr.size);
console.log('之前大小:', prev.size);
});
// 停止监听
fs.unwatchFile('file.txt');watch(推荐)
javascript
const watcher = fs.watch('directory', { recursive: true }, (eventType, filename) => {
console.log('事件类型:', eventType); // 'rename' 或 'change'
console.log('文件名:', filename);
});
// 停止监听
watcher.close();实用工具函数
递归读取目录
javascript
async function readDirRecursive(dir) {
const entries = await fsPromises.readdir(dir, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const fullPath = require('path').join(dir, entry.name);
if (entry.isDirectory()) {
const subFiles = await readDirRecursive(fullPath);
files.push(...subFiles);
} else {
files.push(fullPath);
}
}
return files;
}
// 使用
readDirRecursive('./src').then(files => {
console.log('所有文件:', files);
});确保目录存在
javascript
async function ensureDir(dir) {
try {
await fsPromises.access(dir);
} catch {
await fsPromises.mkdir(dir, { recursive: true });
}
}复制目录
javascript
const path = require('path');
async function copyDir(src, dest) {
await fsPromises.mkdir(dest, { recursive: true });
const entries = await fsPromises.readdir(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
await copyDir(srcPath, destPath);
} else {
await fsPromises.copyFile(srcPath, destPath);
}
}
}总结
Node.js 文件系统操作要点:
- 文件读写:同步、异步回调、Promise 三种方式
- 目录操作:创建、读取、删除目录
- 文件操作:重命名、复制、删除文件
- 流处理:高效处理大文件
- 文件监听:监控文件变化
- 实用工具:递归操作、目录确保等