文件系统操作 #
一、fs 模块概述 #
1.1 引入 fs 模块 #
javascript
const fs = require('fs');
const fsPromises = require('fs').promises;
const path = require('path');
1.2 同步与异步 #
javascript
// 同步操作
const data = fs.readFileSync('file.txt', 'utf-8');
// 异步操作(回调)
fs.readFile('file.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 异步操作(Promise)
const data = await fsPromises.readFile('file.txt', 'utf-8');
二、文件读写 #
2.1 读取文件 #
javascript
const fs = require('fs').promises;
// 读取文本文件
async function readTextFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf-8');
return content;
} catch (error) {
console.error('读取失败:', error);
throw error;
}
}
// 读取 JSON 文件
async function readJsonFile(filePath) {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content);
}
// 读取二进制文件
async function readBinaryFile(filePath) {
const buffer = await fs.readFile(filePath);
return buffer;
}
2.2 写入文件 #
javascript
const fs = require('fs').promises;
// 写入文本文件
async function writeTextFile(filePath, content) {
await fs.writeFile(filePath, content, 'utf-8');
}
// 写入 JSON 文件
async function writeJsonFile(filePath, data) {
const content = JSON.stringify(data, null, 2);
await fs.writeFile(filePath, content, 'utf-8');
}
// 写入二进制文件
async function writeBinaryFile(filePath, buffer) {
await fs.writeFile(filePath, buffer);
}
// 追加内容
async function appendToFile(filePath, content) {
await fs.appendFile(filePath, content, 'utf-8');
}
2.3 流式读写 #
javascript
const fs = require('fs');
// 读取流
function readLargeFile(filePath, onChunk) {
return new Promise((resolve, reject) => {
const stream = fs.createReadStream(filePath, { highWaterMark: 64 * 1024 });
stream.on('data', (chunk) => {
onChunk(chunk);
});
stream.on('end', () => {
resolve();
});
stream.on('error', (error) => {
reject(error);
});
});
}
// 写入流
function writeLargeFile(filePath, getChunks) {
return new Promise((resolve, reject) => {
const stream = fs.createWriteStream(filePath);
const writeChunk = () => {
const chunk = getChunks();
if (chunk) {
stream.write(chunk, writeChunk);
} else {
stream.end();
}
};
stream.on('finish', resolve);
stream.on('error', reject);
writeChunk();
});
}
// 复制文件
function copyFile(source, target) {
return new Promise((resolve, reject) => {
const readStream = fs.createReadStream(source);
const writeStream = fs.createWriteStream(target);
readStream.pipe(writeStream);
writeStream.on('finish', resolve);
writeStream.on('error', reject);
});
}
三、目录操作 #
3.1 创建目录 #
javascript
const fs = require('fs').promises;
// 创建目录
await fs.mkdir('new-dir');
// 递归创建目录
await fs.mkdir('path/to/new/dir', { recursive: true });
3.2 读取目录 #
javascript
const fs = require('fs').promises;
// 读取目录内容
const files = await fs.readdir('directory');
// 带详细信息
const files = await fs.readdir('directory', { withFileTypes: true });
files.forEach(file => {
console.log(file.name);
console.log(file.isFile());
console.log(file.isDirectory());
});
3.3 删除目录 #
javascript
const fs = require('fs').promises;
// 删除空目录
await fs.rmdir('empty-dir');
// 递归删除目录
await fs.rm('directory', { recursive: true, force: true });
3.4 遍历目录 #
javascript
const fs = require('fs').promises;
const path = require('path');
async function walkDirectory(dir, callback) {
const files = await fs.readdir(dir, { withFileTypes: true });
for (const file of files) {
const filePath = path.join(dir, file.name);
if (file.isDirectory()) {
await walkDirectory(filePath, callback);
} else {
await callback(filePath);
}
}
}
// 使用
await walkDirectory('/path/to/dir', async (filePath) => {
console.log(filePath);
});
四、文件信息 #
4.1 获取文件状态 #
javascript
const fs = require('fs').promises;
async function getFileInfo(filePath) {
const stats = await fs.stat(filePath);
return {
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
size: stats.size,
created: stats.birthtime,
modified: stats.mtime,
accessed: stats.atime
};
}
4.2 检查文件存在 #
javascript
const fs = require('fs').promises;
async function fileExists(filePath) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
// 或使用 stat
async function fileExists(filePath) {
try {
await fs.stat(filePath);
return true;
} catch {
return false;
}
}
4.3 获取文件扩展名 #
javascript
const path = require('path');
const ext = path.extname('file.txt'); // '.txt'
const name = path.basename('file.txt', '.txt'); // 'file'
const dir = path.dirname('/path/to/file.txt'); // '/path/to'
五、文件操作 #
5.1 复制文件 #
javascript
const fs = require('fs').promises;
// 复制文件
await fs.copyFile('source.txt', 'target.txt');
// 带标志
await fs.copyFile('source.txt', 'target.txt', fs.constants.COPYFILE_EXCL);
5.2 移动文件 #
javascript
const fs = require('fs').promises;
// 移动/重命名文件
await fs.rename('old-path.txt', 'new-path.txt');
5.3 删除文件 #
javascript
const fs = require('fs').promises;
// 删除文件
await fs.unlink('file.txt');
5.4 截断文件 #
javascript
const fs = require('fs').promises;
// 截断文件到指定长度
await fs.truncate('file.txt', 100);
六、文件权限 #
6.1 修改权限 #
javascript
const fs = require('fs').promises;
// 修改权限
await fs.chmod('file.txt', 0o755);
// 修改所有者
await fs.chown('file.txt', uid, gid);
6.2 检查权限 #
javascript
const fs = require('fs').promises;
const constants = fs.constants;
// 检查可读
await fs.access('file.txt', constants.R_OK);
// 检查可写
await fs.access('file.txt', constants.W_OK);
// 检查可执行
await fs.access('file.txt', constants.X_OK);
// 检查存在
await fs.access('file.txt', constants.F_OK);
七、文件监听 #
7.1 fs.watch #
javascript
const fs = require('fs');
// 监听文件变化
const watcher = fs.watch('file.txt', (eventType, filename) => {
console.log('事件类型:', eventType);
console.log('文件名:', filename);
});
// 关闭监听
watcher.close();
7.2 fs.watchFile #
javascript
const fs = require('fs');
// 轮询监听文件变化
fs.watchFile('file.txt', (curr, prev) => {
console.log('当前修改时间:', curr.mtime);
console.log('之前修改时间:', prev.mtime);
});
// 停止监听
fs.unwatchFile('file.txt');
7.3 监听目录 #
javascript
const fs = require('fs');
const path = require('path');
function watchDirectory(dir, callback) {
const watcher = fs.watch(dir, { recursive: true }, (eventType, filename) => {
const filePath = path.join(dir, filename);
callback(eventType, filePath);
});
return watcher;
}
// 使用
const watcher = watchDirectory('/path/to/dir', (eventType, filePath) => {
console.log(`${eventType}: ${filePath}`);
});
八、路径处理 #
8.1 path 模块 #
javascript
const path = require('path');
// 路径拼接
const fullPath = path.join('/path', 'to', 'file.txt');
// '/path/to/file.txt'
// 解析路径
const parsed = path.parse('/path/to/file.txt');
// {
// root: '/',
// dir: '/path/to',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
// 格式化路径
const formatted = path.format({
dir: '/path/to',
base: 'file.txt'
});
// 规范化路径
const normalized = path.normalize('/path/../to/./file.txt');
// '/to/file.txt'
// 相对路径
const relative = path.relative('/path/to', '/path/from');
// '../from'
// 绝对路径
const absolute = path.resolve('file.txt');
// '/current/working/directory/file.txt'
8.2 跨平台路径 #
javascript
const path = require('path');
// 路径分隔符
console.log(path.sep); // Windows: '\\', Unix: '/'
// 分隔符
console.log(path.delimiter); // Windows: ';', Unix: ':'
// 跨平台路径
const dataPath = path.join(app.getPath('userData'), 'data', 'config.json');
九、临时文件 #
9.1 创建临时文件 #
javascript
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
async function createTempFile(content) {
const tempDir = os.tmpdir();
const tempFile = path.join(tempDir, `temp-${Date.now()}.txt`);
await fs.writeFile(tempFile, content);
return tempFile;
}
9.2 临时目录 #
javascript
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
async function createTempDir() {
const tempDir = os.tmpdir();
const tempPath = path.join(tempDir, `myapp-${Date.now()}`);
await fs.mkdir(tempPath);
return tempPath;
}
十、文件工具类 #
10.1 完整工具类 #
javascript
// fileUtils.js
const fs = require('fs').promises;
const path = require('path');
class FileUtils {
static async exists(filePath) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
static async readJson(filePath) {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content);
}
static async writeJson(filePath, data) {
const content = JSON.stringify(data, null, 2);
await fs.writeFile(filePath, content, 'utf-8');
}
static async ensureDir(dirPath) {
if (!(await this.exists(dirPath))) {
await fs.mkdir(dirPath, { recursive: true });
}
}
static async copyDir(src, dest) {
await this.ensureDir(dest);
const entries = await fs.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 this.copyDir(srcPath, destPath);
} else {
await fs.copyFile(srcPath, destPath);
}
}
}
static async removeDir(dirPath) {
await fs.rm(dirPath, { recursive: true, force: true });
}
static async getFiles(dirPath, ext = null) {
const files = [];
const entries = await fs.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
const subFiles = await this.getFiles(fullPath, ext);
files.push(...subFiles);
} else if (!ext || path.extname(fullPath) === ext) {
files.push(fullPath);
}
}
return files;
}
static async getFileSize(filePath) {
const stats = await fs.stat(filePath);
return stats.size;
}
static formatSize(bytes) {
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
let i = 0;
while (bytes >= 1024 && i < units.length - 1) {
bytes /= 1024;
i++;
}
return `${bytes.toFixed(2)} ${units[i]}`;
}
}
module.exports = FileUtils;
10.2 使用工具类 #
javascript
const FileUtils = require('./fileUtils');
// 检查文件存在
if (await FileUtils.exists('config.json')) {
const config = await FileUtils.readJson('config.json');
}
// 确保目录存在
await FileUtils.ensureDir('/path/to/dir');
// 获取所有 JS 文件
const jsFiles = await FileUtils.getFiles('/path/to/dir', '.js');
// 格式化文件大小
const size = FileUtils.formatSize(1024 * 1024); // '1.00 MB'
十一、总结 #
11.1 核心要点 #
| 要点 | 说明 |
|---|---|
| fs.promises | 推荐使用 Promise API |
| 流式读写 | 大文件使用流处理 |
| 路径处理 | 使用 path 模块跨平台 |
| 错误处理 | 始终处理文件操作错误 |
| 文件监听 | watch/watchFile 监听变化 |
11.2 下一步 #
现在你已经掌握了文件系统操作,接下来让我们学习 数据库集成,深入了解 Electron 应用中的数据库使用!
最后更新:2026-03-28