fs (File system) 是文件系统模块,用于操作文件和目录。
支持同步 (sync) 或者异步 (async/callback) 调用,其中同步调用会阻塞主线程,异步调用不会阻塞。
下面分别是 3 种写法,日常开发中常用 同步操作 和 Promise形式异步操作。
import fs from 'fs'
// 同步读取
const syncData = fs.readFileSync('./test.txt', 'utf-8')
console.log('====sync read====')
console.log(syncData)
// 回调形式 异步读取
fs.readFile('./test.txt', 'utf-8', (err, callbackData) => {
if (!err) {
console.log('====callback read====')
console.log(callbackData)
}
})
// promise形式 异步读取
fs.promises.readFile('./test.txt', 'utf-8').then((promiseData) => {
console.log('====promise read====')
console.log(promiseData)
})
// promise 形式还可以是如下写法(常用)
// import fs from 'fs/promises' //注意:使用promise形式的时候必须引用该模块
// fs.readFile('./test.txt', 'utf-8').then((promiseData) => {
// console.log('====promise read====')
// console.log(promiseData)
// })
1 文件操作
1.1 读取文件
fs.readFileSync 基础用法如下:
- 参数 1:设置要读取的文件路径 (相对或者绝对);
- 参数 2:设置读取的编码格式。
import fs from 'fs'
const txtContent = fs.readFileSync('./test.txt', 'utf-8')
以二进制形式读取,操作:
const buf = fs.readFileSync('./test.txt')
// 打印Buffer大小
console.log(buf.length)
// 修改前2个字符
buf.write('gg')
// 输出修改后的内容
console.log(buf.toString())
1.2 写入文件
基础用法如下 fs.writeFileSync:
- 参数 1:输出文件路径;
- 参数 2:输出内容;
- 参数 3 (可选):编码格式。
fs.writeFileSync('./newTest.txt', 'hello world')
修改前的文件:
修改后的文件:
写入二进制文件 (读取一个图片,然后输出到一个新的位置)
// 读取一个图片
const imgBuf = fs.readFileSync('./logo.png')
console.log('isBuffer', Buffer.isBuffer(imgBuf), 'bufferSize', imgBuf.length)
// 写入到新文件
fs.writeFileSync('newLogo.png', imgBuf, 'binary')
修改前img目录文件:
修改后的img目录文件:
运行后的输出:
1.3 获取文件信息
通过 fs.statSync 获取文件或者目录的基本信息。
import fs from 'fs'
console.log(fs.statSync('./test.txt'))
console.log(fs.statSync('./img'))
返回的对象属性如下:
常用字段的意义如下:
返回的对象上还包含可直接调用的方案,用于判断文件类型:
const fileInfo = fs.statSync('./test.txt')
// 判断是文件还是目录
console.log(fileInfo.isFile(), fileInfo.isDirectory())
const dirInfo = fs.statSync('./img')
// 判断是文件还是目录
console.log(dirInfo.isFile(), dirInfo.isDirectory())
try {
// 查询一个不存在的文件/目录信息(会抛出异常,需要自行捕获)
fs.statSync('not_exist.txt')
} catch (e) {
console.log('文件不存在')
}
1.4 追加输出
使用 fs.appendFileSync 向文件末尾追加写入内容。
// 引入文件系统模块
import fs from 'fs';
// 使用 fs.appendFileSync() 方法向指定文件追加内容
// 参数1:指定文件路径
// 参数2:要追加的内容
fs.appendFileSync('test.txt', 'Hello World2!');
修改前的文件:
修改后的文件:
1.5 移动/重命名文件
fs.renameSync 方法用于文件移动,当然也可以是重命名文件。
下面是文件重命名示例。
import fs from 'fs'
fs.renameSync('test.txt', 'test2.txt')
修改前的目录:
修改后端的目录:
下面是移动文件示例:
fs.renameSync('test2.txt', 'test-dir/test2.txt')
移动后的文件出现的位置:
1.6 删除文件
fs.unlinkSync 和 fs.rmSync 都可用于单文件删除。
import fs from 'fs'
fs.unlinkSync('test-dir/test2.txt')
// fs.rmSync('test-dir/test2.txt')
删除文件前的目录:
删除文件后的目录:
当然后者还支持删除目录,递归删除子文件/目录等。
// 删除 test-dir 目录(包含其子文件)
fs.rmSync('test-dir', { recursive: true })
删除前的目录:
删除后的目录:
2 目录操作
2.1 读取目录所有文件
通过 fs.readdirSync 获取目录下的文件信息。
import fs from 'fs'
const files = fs.readdirSync('test-dir')
console.log(files)
被读取的目录:
读取目录后的结果:
可通过指定第二个参数 withFileTypes:true 使返回结果包含类型:
const files2 = fs.readdirSync('test-dir', { withFileTypes: true })
console.log(files2.map((f) => ({ name: f.name, isDirectory: f.isDirectory() })))
2.2 创建目录
使用 fs.mkdirSync 创建目录,可通过设置 recursive:true 来递归创建多级目录。
fs.mkdirSync('test-dir/a/b/c/d', { recursive: true })
创建新的目录前:
创建新的目录后:
2.3 删除目录
可以使用 fs.rmdirSync 删除目标目录,recursive: true 表明删除包含其子目录。
fs.rmdirSync('test-dir/a', { recursive: true })
删除目录前:
删除目录后:
也可以使用上面提到的 fs.rmSync:
fs.rmSync('test-dir/a', { recursive: true })
2.4 监听目录变更
利用 fs.watch 即可实现。
import fs from 'fs'
// 监听当前目录下所有的文件和子目录中的文件
fs.watch('./', { recursive: true }, (eventType, filename) => {
console.log(`File '${filename}' has changed: ${eventType}`)
})
小结
本小节先简单介绍了三种调用文件系统 API 的方式:
- 同步 (Sync):例如 fs.readFileSync,会阻塞主线程;
- 异步 (Async/Callback):fs.promises.readFile,fs.readFile,不会阻塞主线程。
日常使用中推荐使用 fs/promise 的方式。
紧接着分别介绍了文件和目录的常规的 CRUD 方法,
最后综合运用上面介绍的方法,解决一个常见场景问题获取指定目录下所有文件的绝对路径 。