概述
在 Node.js 中,fs
模块是文件系统模块(File System module)的缩写,它提供了与文件系统进行交互的各种功能。通过 fs
模块,你可以执行诸如读取文件、写入文件、更改文件权限、创建目录等操作,Node.js 核心API之一
。
fs多种策略
import fs from 'node:fs' import fs2 from 'node:fs/promises' //读取文件 fs2.readFile('./index.txt').then(result => { console.log(result.toString()) }) fs.readFile('./index.txt', (err, data) => { if (err) { return err } console.log(data.toString()) }) let txt = fs.readFileSync('./index.txt') console.log(txt.toString())
- fs支持同步和异步两种模式 增加了
Sync
fs 就会采用同步的方式运行代码,会阻塞下面的代码,不加Sync就是异步的模式不会阻塞。 - fs新增了promise版本,只需要在引入包后面增加/promise即可,fs便可支持promise回调。
- fs返回的是一个buffer二进制数据 每两个十六进制数字表示一个字节
<Buffer 31 e3 80 81 e9 82 a3 e4 b8 80 e5 b9 b4 e5 86 b3 e8 b5 9b ef bc 8c e6 98 af 53 53 47 e5 af b9 e6 88 98 53 4b 54 ef bc 8c e6 9c 80 e7 bb 88 e6 af 94 e5 ... 635 more bytes>
常用API 介绍
读取文件 readFile 读一个参数 读取的路径, 第二个参数是个配置项
encoding 支持各种编码 utf-8之类的
flag 就很多了
'a'
: 打开文件进行追加。 如果文件不存在,则创建该文件。'ax'
: 类似于'a'
但如果路径存在则失败。'a+'
: 打开文件进行读取和追加。 如果文件不存在,则创建该文件。'ax+'
: 类似于'a+'
但如果路径存在则失败。'as'
: 以同步模式打开文件进行追加。 如果文件不存在,则创建该文件。'as+'
: 以同步模式打开文件进行读取和追加。 如果文件不存在,则创建该文件。'r'
: 打开文件进行读取。 如果文件不存在,则会发生异常。'r+'
: 打开文件进行读写。 如果文件不存在,则会发生异常。'rs+'
: 以同步模式打开文件进行读写。 指示操作系统绕过本地文件系统缓存。
这主要用于在 NFS 挂载上打开文件,因为它允许跳过可能过时的本地缓存。 它对 I/O 性能有非常实际的影响,因此除非需要,否则不建议使用此标志。
这不会将fs.open()
或fsPromises.open()
变成同步阻塞调用。 如果需要同步操作,应该使用类似fs.openSync()
的东西。'w'
: 打开文件进行写入。 创建(如果它不存在)或截断(如果它存在)该文件。'wx'
: 类似于'w'
但如果路径存在则失败。'w+'
: 打开文件进行读写。 创建(如果它不存在)或截断(如果它存在)该文件。'wx+'
: 类似于'w+'
但如果路径存在则失败。
import fs2 from 'node:fs/promises' fs2.readFile('./index.txt',{ encoding:"utf8", flag:"", }).then(result => { console.log(result.toString()) })
使用可读流读取 使用场景适合读取大文件
const readStream = fs.createReadStream('./index.txt',{ encoding:"utf8" }) readStream.on('data',(chunk)=>{ console.log(chunk) }) readStream.on('end',()=>{ console.log('close') })
创建文件夹 如果开启 recursive 可以递归创建多个文件夹
fs.mkdir('path/test/ccc', { recursive: true },(err)=>{ })
删除文件夹 如果开启recursive 递归删除全部文件夹
fs.rm('path', { recursive: true },(err)=>{ })
重命名文件 第一个参数原始名称 第二个参数新的名称
fs.renameSync('./test.txt','./test2.txt')
监听文件的变化 返回监听的事件如change
,和监听的内容filename
fs.watch('./test2.txt',(event,filename)=>{ console.log(event,filename) })
源码解析
https://github.com/libuv/libuv
fs的源码是通过 C++
层的 FSReqCallback
这个类 对libuv
的uv_fs_t
的一个封装,其实也就是将我们fs 的参数透传给 libuv
层
mkdir 举例
// 创建目录的异步操作函数,通过uv_fs_mkdir函数调用 // 参数: // - loop: 事件循环对象,用于处理异步操作 // - req: 文件系统请求对象,用于保存操作的状态和结果 // - path: 要创建的目录的路径 // - mode: 目录的权限模式 777 421 // - cb: 操作完成后的回调函数 int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode, uv_fs_cb cb) { INIT(MKDIR); PATH; req->mode = mode; if (cb != NULL) if (uv__iou_fs_mkdir(loop, req)) return 0; POST; }
注意事项
const fs = require('node:fs') fs.readFile('./index.txt', { encoding: 'utf-8', flag: 'r' }, (err, dataStr) => { if (err) throw err console.log('fs') }) setImmediate(() => { console.log('setImmediate') })
为什么先走setImmediate 呢,而不是fs
Node.js 读取文件的时候是使用libuv进行调度的
而setImmediate是由V8进行调度的
文件读取完成后 libuv 才会将 fs的结果 推入V8的队列