>[success] # 内置模块fs
1. fs是`File System`的缩写,表示文件系统,文件读取、写入、复制、重命名、删除、文件权限的设置等一系列的操作方法
2. 这些API大多数都提供三种操作方式
* **同步操作文件**:代码会被阻塞,不会继续执行;
* **异步回调函数操作文件**:代码不会被阻塞,需要传入回调函数,当获取到结果时,回调函数被执行
* **异步Promise操作文件**:代码不会被阻塞,通过 fs.promises 调用方法操作,会返回一个Promise,可以通过then、catch进行处理
3. 关于`fs.promises` 风格,在 Node.js 14.x 版本中,许多 `fs` 模块的 API 都添加了 `fs.promises` 的支持,这意味着您可以使用类似 `fs.promises.readFile` 这样的 Promise 风格的异步 API 来代替传统的回调函数式异步 API。使用 `fs.promises` 可以方便地使用 async/await 语法糖来处理异步操作,从而使异步编程更加简单易懂。 但是,您需要注意的是,并非所有的 `fs` 模块的 API 都支持 `fs.promises`。例如,`fs.read` 和 `fs.write` 这两个 API 就不支持 `fs.promises`,因此只能使用传统的回调函数式异步 API 或者同步 API 来进行操作。 如果您需要使用同步 API,可以使用同名同参数的 API 来代替异步 API。例如,使用 `fs.readFileSync` 来代替 `fs.promises.readFile`,使用 `fs.mkdirSync` 来代替 `fs.promises.mkdir`。需要注意的是,同步 API 会阻塞程序的执行,因此需要谨慎使用,特别是在 IO 密集型的场景下。
4. 正常的同步api 和 通过async await 实现的同步`fs.promises` 有什么区别?举个例子
~~~
const fs = require('fs')
async function readA() {
const a = await fs.promises.readFile('a.txt')
console.log(a)
}
const b = fs.readFileSync('a.txt')
readA()
console.log(b)
~~~
变量 b 是通过 `fs.readFileSync` 同步地读取文件内容得到的,因此当执行到 `console.log(b)` 时,**文件内容已经被完全读取并存储在变量 b 中,可以直接输出**。 相比之下,变量 a 是通过 `fs.promises.readFile` 异步地读取文件内容得到的。在执行到 `readA()` 时,**虽然异步读取文件的操作已经开始,但此时文件内容还没有被完全读取并存储在变量 a 中**,使用了 `await `的异步操作本质上仍然是异步的,只不过是使用了 `Promise `和 `async/await` 语法糖来简化异步编程的复杂度。因此,虽然使用了 `await`,变量 a 仍然是异步读取文件得到的结果,和 b 的同步读取结果有本质的区别。 具体来说,使用 `await `的异步操作会立即返回一个 `Promise `对象,在异步操作完成后,`Promise `对象的状态会从 `pending `变为 `fulfilled `或 `rejected`,并将异步操作的结果传递给 `Promise `的 then 方法或者 `catch `方法。在 `await `后的表达式中,如果 `Promise `的状态为 `fulfilled`,则会返回 `Promise `绑定的值;如果 `Promise `的状态为 `rejected`,则会抛出 `Promise `绑定的错误。 因此,在这段代码中,当执行到 `await fs.promises.readFile('a.txt')` 时,异步读取文件操作已经开始,但由于此时文件内容还未被完全读取,因此 `await `表达式会暂停代码的执行,直到异步操作完成并返回 `Promise `对象后,再继续执行下面的代码因此**变量 a 是异步读取文件的结果,和变量 b 的同步读取结果有本质的区别。**
| API | 描述 | 同步/异步 | fs.promises 调用方法 |
| --- | --- | --- | --- |
| fs.readFile(path \[, options\], callback) | 异步读取文件内容 | 异步 | fs.promises.readFile(path \[, options\]) |
| fs.readFileSync(path \[, options\]) | 同步读取文件内容 | 同步 | fs.promises.readFile(path \[, options\]) |
| fs.writeFile(file, data \[, options\], callback) | 异步写入文件内容 | 异步 | fs.promises.writeFile(file, data \[, options\]) |
| fs.writeFileSync(file, data \[, options\]) | 同步写入文件内容 | 同步 | fs.promises.writeFile(file, data \[, options\]) |
| fs.mkdir(path \[, options\], callback) | 异步创建目录 | 异步 | fs.promises.mkdir(path \[, options\]) |
| fs.mkdirSync(path \[, options\]) | 同步创建目录 | 同步 | fs.promises.mkdir(path \[, options\]) |
| fs.readdir(path \[, options\], callback) | 异步读取目录下的所有文件和子目录 | 异步 | fs.promises.readdir(path \[, options\]) |
| fs.readdirSync(path \[, options\]) | 同步读取目录下的所有文件和子目录 | 同步 | fs.promises.readdir(path \[, options\]) |
| fs.stat(path, callback) | 异步获取文件或目录的状态信息 | 异步 | fs.promises.stat(path) |
| fs.statSync(path) | 同步获取文件或目录的状态信息 | 同步 | fs.promises.stat(path) |
| fs.rename(oldPath, newPath, callback) | 异步重命名文件 | 异步 | fs.promises.rename(oldPath, newPath) |
| fs.renameSync(oldPath, newPath) | 同步重命名文件 | 同步 | fs.promises.rename(oldPath, newPath) |
| fs.unlink(path, callback) | 异步删除文件 | 异步 | fs.promises.unlink(path) |
| fs.unlinkSync(path) | 同步删除文件 | 同步 | fs.promises.unlink(path) |
| fs.rmdir(path, callback) | 异步删除目录 | 异步 | fs.promises.rmdir(path) |
| fs.rmdirSync(path) | 同步删除目录 | 同步 | fs.promises.rmdir(path) |
| fs.createReadStream(path \[, options\]) | 创建可读流 | 异步 | fs.promises.createReadStream(path \[, options\]) |
| fs.createWriteStream(path \[, options\]) | 创建可写流 | 异步 | fs.promises.createWriteStream(path \[, options\]) |
| fs.watchFile(filename \[, options\], listener) | 监听文件变化 | 异步 | \- |
| fs.unwatchFile(filename \[, listener\]) | 取消监听文件变化 | 异步 | \- |
| fs.watch(filename \[, options\], listener) | 监听文件系统事件 | 异步 | \- |
| fs.access(path \[, mode\], callback) | 测试用户对 path 指定的文件或目录的权限 | 异步 | fs.promises.access(path \[, mode\]) |
| fs.accessSync(path \[, mode\]) | 测试用户对 path 指定的文件或目录的权限 | 同步 | fs.promises.access(path \[, mode\]) |
>[danger] ##### 知识补充
`fs.read` 和 `fs.write` 这两个 API 并不支持 `fs.promises` 的主要原因是它们是基于底层操作系统提供的文件读写接口的,而这些接口通常是异步的,因此无法直接使用 Promise 风格的 API。 这两个 API 都是使用回调函数的方式实现异步操作的。例如,`fs.read` 方法的语法如下:
~~~javascript
fs.read(fd, buffer, offset, length, position, callback)
~~~
其中,`callback` 参数是一个回调函数,它在文件读取完成后被调用,通常会将读取到的数据和读取字节数作为参数传递给回调函数。类似地,`fs.write` 方法也是使用回调函数的方式实现异步操作的,它的语法如下:
~~~javascript
fs.write(fd, buffer, offset, length, position, callback)
~~~
由于这两个 API 是基于底层操作系统提供的接口实现的,因此无法直接使用 Promise 风格的 API。如果您希望使用 Promise 风格的 API,可以考虑使用 `fs.promises.readFile` 和 `fs.promises.writeFile` 这两个方法来实现文件读写操作,它们都是支持 Promise 风格的异步 API。
*****
`fs.write` 和 `fs.writeFile` 两者的主要区别在于:
1. 使用方式不同 `fs.write` 方法需要打开文件描述符,然后通过该文件描述符进行写入操作。它的语法如下:
~~~javascript
fs.write(fd, buffer[, offset[, length[, position]]], callback)
~~~
其中,`fd` 是文件描述符,`buffer` 是一个 `Buffer` 或 `Uint8Array` 对象,`offset` 和 `length` 分别表示要写入的数据在 `buffer` 中的偏移量和长度,`position` 表示写入的起始位置。最后一个参数是回调函数,它在写入完成后被调用。 相比之下,`fs.writeFile` 方法则更加简单,只需要指定文件路径和要写入的数据即可。它的语法如下:
~~~javascript
fs.writeFile(file, data[, options], callback)
~~~
其中,`file` 是文件路径,`data` 是要写入的数据,`options` 是一个可选的配置对象,`callback` 是写入完成后的回调函数。 2. 写入方式不同 `fs.write` 方法是基于文件描述符进行写入操作的,它可以使用多种写入方式,例如:
* `fs.write(fd, buffer, offset, length, position, callback)`:向指定位置写入数据。
* `fs.write(fd, data, callback)`:向当前文件指针位置写入数据。
* `fs.write(fd, buffer[, offset[, length[, position]]])`:向当前文件指针位置写入数据,并将文件指针移动到写入数据的末尾。 相比之下,`fs.writeFile` 方法只支持一种写入方式,即向文件中写入指定的数据,如果文件已经存在,则会覆盖原有的数据。 因此,如果您需要对一个已经打开的文件进行写入操作,或者需要对一个文件进行复杂的写入操作(例如随机访问或追加写入),则应该使用 `fs.write` 方法。如果您只需要向文件中写入指定的数据,并且不需要进行复杂的写入操作,则可以使用 `fs.writeFile` 方法。
- 基础
- 什么是Node.js
- 理解 I/O 模型
- 理解node 中 I/O
- 对比node 和java 使用场景
- node 模块管理
- 内置模块 -- buffer
- 内置模块 -- fs
- fs -- 文件描述符
- fs -- 打开文件 api
- fs -- 文件读取 api
- fs -- 文件写入 api
- fs -- 创建目录 api
- fs -- 读取文件目录结构 api
- fs -- 文件状态(信息) api
- fs -- 删除文件/目录 api
- fs -- 重命名 api
- fs -- 复制文件 api
- 内置模块 -- events
- 内置模块 -- stream
- 可读流 -- Readable
- 可写流 -- Writable
- Duplex
- Transform
- 内置模块 -- http
- http -- 从客户端发起
- http -- 从服务端发起
- 内置模块 -- url
- 网络开发