文件系统
关于文件系统的学习,主要是学习其为我们所提供的api相关的操作,因为它的实现是借由底层的c++层来实现的,node.js中的文件系统fs仅仅是通过相关的调用以及规则的限制来更加方便的使用宿主环境的文件资源的! 关于node.js所提供的文件模块主要可以分为三类:异步回调、promise的调用、同步调用,异步回调与promise的调用主要也是node.js所提供的异步I/O机制的方式来使用的,而同步调用则必须等到异步I/O的执行 完毕后,才能继续后续的操作,也就是这个这里同步回调将会消耗掉js执行CPU时间,让程序卡住,这个对于单线程的js来说,需要慎重地来使用,除非是明确规定说所有的操作都必须在这个同步操作之后,否则一般是采用 异步回调的方式来实现,本文章也主要是按照正常的异步回调的方式来学习关于node.js中的文件系统模块(这里将统称为xxx系列方法)! 这里展示关于三种文件系统模块的使用方式 异步回调使用:
const { appendFile } = require('node:fs');
promise调用使用:const { promiseFs } = require('node:fs/promises');
同步调用使用:const { readSync } = require('node:fs');
关于三者使用的区别如下
const { appendFile, appendFileSync } = require('node:fs');
const { promiseFs } = require('node:fs/promises');
appendFile('file', '要写入的内容',err => {
// 异常回调
});
const result = appendFileSync('file', '要写入的内容'); // 等待执行结果
let fileHandle;
try{
fileHandle = await promiseFs.open('file'); // 异步等待打开文件
const result = await fileHandle.appendFile('要写入的内容'); // 异步等待写入内容
}catch(exception){}finally {
await fileHandle?.close();
}
这里我们可以发现,异步回调与同步执行除了方法名称上多了一个Sync
之外,其他的在使用上表面上看没有啥区别,而promise的调用则是基于FileHandle
对象的,任何在该对象上的操作都采用promise的方式来执行的,
这里有点像是
const { fs } = require('node:fs');
promiseFs.appendFile = function(data) {
return new Promise((resolve, reject) => {
fs.appendFile(data, err => {
if(!err){
reject(err);
}else{
resolve();
}
})
});
}
这意味着我们也可以在fs的基础上,将其所有的api以自己的一套方式,来将所有的api方法给进行promise化!!
关于这个fs模块,它其中 关于f开头的系列方法,代表着它是主要已fd句柄来进行文件操作的API方法!!
相关的辅助对象
来一一介绍关于文件系统中相关辅助对象
Dir文件夹流对象
代表的文件夹对象,一般由open()系列函数所创建,且对于该对象,语序使用
迭代器
来遍历其中的孩子元素,因为其内部定义了相关的迭代器api操作,使得其允许通过for...of
的方式来遍历该元素,实际上调用的是它的迭代器方法, 如下代码所示:
const { opendir } = require('node:fs'); opendir('./', (err, dir) => { if(err){ console.info(err); }else{ console.info(dir); let it = dir.entries(); it.next().then(res => { console.info(res); it.next().then(res => { console.info(res); it.next().then(res => { console.info(res); it.next().then(res => { console.info(res); it.next().then(res => { console.info(res); }) }) }) }) }) } });
这里我们通过调用dir的
entries
方法获取到其文件夹迭代器,然后我们可以通过next()方法,来与之"步进式"
的方式来执行,原因如下图所示:
一般可使用该对象类遍历其中的各个孩子文件(夹)
Dirent文件对象
这里则是通过执行其迭代器中的实例方法,返回的每一个孩子元素的Dirent文件对象,代表的是每一个文件对象,也可以通过
readdir
的方式来返回这个文件对象(必须设置对应的参数属性才能正常返回),
FSWatcher文件观察者对象
通过
fs.watch()
方法返回的,用于监听一个文件(夹)是否发生了变化,根据该对象所提供的change
监听方法,可用于监听相关与文件有关的操作、callback中的eventType事件类型和文件名称。 既然它是具有监听操作的对象,那么 是否意味着它与EventEmitter
对象有关联呢?答案是肯定的!通过观察源码我们可以晓得: FSWatcher对象直接继承于EventEmitter对象,利用该对象所提供的on
+emit
方法,可以进行对其进行监听,其中内部调用的是对象中的_handle
对象, node.js中主要用该对象来与c++底层进行的通讯,同时在该对象中提供的onchange
方法,主要是通过实现的该方法来实现对c++层的响应处理动作, 从而来将结果emit给到监听者!
StatWatcher文件属性观察者对象
基本上与 的
FSWatcher
对象一致!!
fs.ReadStream文件可读流对象
与stream模块中的可读流使用上基本一致,因为它其实就是直接new stream.ReadableStream的方式来创建的, 在stream中的ReadStream是怎样的,在fs中的就是怎样的一个对象!!!
fs.WriteStream文件可写流对象
同fs.ReadStream对象类似
Stats文件基础信息对象
文件基础信息对象,一般由
fs.stat()
、fs.lstat()
、fs.fstat()
方法返回的!
fs.constants文件模块枚举对象
文件系统中经常使用的常量枚举变量,一般用于在调用fs的相关api操作时,通过传递对应的枚举值来进行控制对应的读、写、执行操作,可通过access方法api来配置,或者是各个api在调用的时候,传递对应的参数即可!! 比如 的例子:
const { open, constants } = require('node:fs'); const { O_RDWR, O_CREAT, O_EXCL } = constants; open('file', O_RDWR | O_CREAT | O_EXCL, (err, fd) => {});
关于这个所有的枚举,可以从
node.js的源码/typing/internalBinding/constants.d.ts
文件中浏览
相关的API以及对象一览
这里不针对官方的文档直接做翻译了,直接根据官方的学习文档,这里以下对应的关于node.js中的文件系统模块,这里仅列出异步回调相关的