| 学习路线指引(点击解锁) | 知识定位 | 人群定位 |
|---|---|---|
| 🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
| 💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
文件系统是一种用于向用户提供底层数据访问的机制,同时也是一套实现了数据的存储、分级组织、访问和获取等操作的抽象数据类型。
Node.js 中的fs模块就是对文件系统的封装,整合了一套标准 POSIX 文件 I/O 操作的集合,包括文件的读写、删除、遍历、重命名等操作。
fs 模块中的所有方法都提供了三种形式:回调、同步和 Promise ,其中 Promise 是在 Node.js 的版本 10 中引入的。
本系列所有的示例源码都已上传至Github,点击此处获取。
在回调形式的方法中,最后一个参数是其回调函数,会异步地调用,其中回调函数的第一个参数始终为异常预留,不过有个例外是 exists() 方法。
回调形式不容易书写,很容易就会形成回调地狱。
虽然同步形式的方法比较容易书写,但是在执行时会阻止 Node.js 事件循环和阻塞 JavaScript 执行,直到操作完成。
Promise 形式的方法会使用底层的 Node.js 线程池,在事件循环线程之外异步地执行文件系统操作。对同一文件执行多个并发修改时必须小心,有可能会损坏数据。
以读取文件为例,三种形式的写法如下所示,若不指定编码,那么输出的将是 Buffer 实例。
const fs = require('fs');
// 回调
fs.readFile('./data.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data); // strick
});
// 同步
const data = fs.readFileSync('./data.txt', 'utf8');
console.log(data); // strick
// Promise
const { promises } = fs;
async function readFilePromise() {
const data = await promises.readFile('./data.txt', 'utf8');
console.log(data); // strick
}
readFilePromise();
1)判断文件是否存在
exists() 方法可用于判断文件是否存在,但在上一小节中曾提到,它已被弃用。
这是因为此回调的参数与其他回调不一致。通常,Node.js 回调的第一个参数是 err 参数,然后跟可选的其他参数,但 fs.exists() 回调只有一个布尔参数,如下所示。
fs.exists('./data.txt', isExist => {
console.log(isExist);
});
再则是因为 exists() 方法的功能用 access() 方法也能实现,其内部源码如下所示,其实也是调用了 access() 方法。
function exists(path, callback) {
maybeCallback(callback);
// 构造回调函数
function suppressedCallback(err) {
callback(err ? false : true);
}
try {
fs.access(path, F\_OK, suppressedCallback);
} catch {
return callback(false);
}
}
其中 F_OK 是 fs 模块中的一个常量,表示文件是否存在,使用方法如下所示,R_OK 表示是否可读,W_OK 表示是否可写。
const { constants } = require('fs');
const { F\_OK, R\_OK, W\_OK } = constants;
注意,在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,不能使用 fs.access() 检查文件是否存在。
因为这样做会引入竞争条件,其他进程可能会在两次调用之间修改文件状态,造成非预期的结果。
遇到这种场景,推荐的做法是直接打开、读取或写入文件,当文件不可用时再做处理。
另一种判断文件是否存在的方法是调用 stat(),读取文件属性。
它有两个方法 isDirectory() 和 isFile() 可分别判断是否是目录和是否是文件,如下所示。
fs.stat('./data.txt', (err, stats) => {
console.log(stats.isDirectory());
console.log(stats.isFile());
});
同样要注意的是,它也不能在调用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,检查文件是否存在。
2)方法
下面罗列的是 fs 模块的一些方法。
3)路径
路径处理并不是在 fs 模块,而是在path模块,它的方法包括。
path.basename('../06/data.txt') // data.txt
path.dirname('../06/data.txt'); // ../06
path.extname('../06/data.txt'); // .txt
path.isAbsolute('../06/data.txt'); // false
path.join('../', '06', 'data.txt'); // ../06/data.txt
path.normalize('/../06/data.txt'); // /06/data.txt
// { root: '', dir: '../06', base: 'data.txt', ext: '.txt', name: 'data' }
path.parse('../06/data.txt');
path.relative('../', '../06/data.txt'); // 06/data.txt
path.resolve('../06/data.txt'); // /Users/code/web/node/06/data.txt
参考资料: