fs 模块
文章目录
- [fs 模块](#fs 模块)
-
- 一、文件写入
-
- [1-1.writeFile 异步写入](#1-1.writeFile 异步写入)
- [1-2.writeFileSync 同步写入](#1-2.writeFileSync 同步写入)
- [1-3.appendFile / appendFileSync 追加写入](#1-3.appendFile / appendFileSync 追加写入)
- [1-4.createWriteStream 流式写入](#1-4.createWriteStream 流式写入)
- 1-5.写入文件的场景
- 二、文件读取
-
- [2-1.readFile 异步读取](#2-1.readFile 异步读取)
- [2-2.readFileSync 同步读取](#2-2.readFileSync 同步读取)
- [2-3.createReadStream 流式读取](#2-3.createReadStream 流式读取)
- 2-4.读取文件应用场景
- 三、文件移动与重命名
- 四、文件删除
- 五、文件夹操作
-
- [5-1. mkdir 创建文件夹](#5-1. mkdir 创建文件夹)
- [5-2.readdir 读取文件夹](#5-2.readdir 读取文件夹)
- [5-3.rmdir 删除文件夹](#5-3.rmdir 删除文件夹)
- 六、查看资源状态
- 七、相对路径问题
- 八、__dirname
- 九、练习
fs 全称为 file system
,称之为 文件系统
,是 Node.js 中的 内置对象
,可以对计算机中的磁盘进行操作。
fs 模块可以实现与硬盘的交互。例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作。
推荐一个插件:Template String Converter
该插件可以自动将字符串转换为模板字符串的形式
本章的学习重点:
- 文件写入
- 文件读取
- 文件移动与重命名
- 文件删除
- 文件夹操作
- 查看资源状态
一、文件写入
文件写入就是将 数据
保存在 文件
中,我们可以使用如下几个方法来实现该效果。
方法 | 说明 |
---|---|
writeFile | 异步写入 |
writeFileSync | 同步写入 |
appendFile / appendFileSync | 追加写入 |
createWriteStream | 流式写入 |
1-1.writeFile 异步写入
语法: fs.writeFile(file, data[, options], callback)
参数说明:
- file:文件名
- data:待写入的数据
- options:选项设置
可选
- callback:写入回调函数
返回值: undefined
代码示例:
js
// 1.导入 fs 模块
// require 是 Node.js 环境中的'全局'变量,用来导入模块
const fs = require('fs')
// 2.写入文件
// 将『三人行,必有我师焉。』写入到当前文件夹下的『座右铭.txt』文件中
fs.writeFile('../FileWrite/座右铭.txt', '三人行,必有我师焉。', err => {
// err:如果写入失败,则回调函数调用时,会传入错误对象;如果写入成功,会传入 null
if(err) {
console.log('写入失败')
return
}
console.log('写入成功')
})
如何看到 writeFile 的异步写入效果:(我们可以在上述代码的最后加上如下代码)
js
console.log(1 + 1)
通过结果可以看出:先输出的 console,再是回调函数

1-2.writeFileSync 同步写入
语法: fs.writeFileSync(file, data[, options])
参数与 fs.writeFile
大体一样,只是没有 callback
参数
返回值: undefined
代码示例:
js
// 1.导入 fs 模块
const fs = require('fs')
// 2.写入文件
try {
fs.writeFileSync('../FileWrite/text.txt', 'test')
} catch (error) {
console.log(error)
}
Node.js 中的磁盘操作是由其他
线程
完成的,结果的处理有两种模式:
- 同步处理: JavaScript 主线程
会等待
其他线程的执行结果,然后再继续执行主线程的代码,效率较低
- 异步处理: JavaScript 主线程
不会等待
其他线程的执行结果,直接执行后续的主线程代码,效率较好
1-3.appendFile / appendFileSync 追加写入
appendFile / appendFileSync 的作用是在文件尾部追加内容,appendFile 语法与 writeFile 语法完全相同;而 appendFileSync 语法则与 writeFileSync 语法完全相同。
语法:
fs.appendFile(file, data[, options], callback)
fs.appendFileSync(file, data[, options])
返回值: 二者都为 undefined
实例代码:
js
// 1.引入 fs 模块
const fs = require('fs')
// 2.调用 appendFile,其语法和 writeFile 完全相同
fs.appendFile('../FileWrite/座右铭.txt', '择期善者而改之,择期不善者而改之。', err => {
// 判断
if(err) {
console.log('写入失败~~')
return
}
console.log('写入成功~~')
})
// 还可以使用 appendFileSync,其语法和 writeFileSync 完全相同
// 加上\r\n,可以实现追加内容换行
fs.appendFileSync('./FileWrite/座右铭.txt', '\r\n温故而知新,可以为师矣。')
此外,我们还可以通过
writeFile
来实现文件追加写入。具体代码如下所示:
js
const fs = require('fs')
// 使用 writeFile 也可以实现追加写入(需要使用到第三个参数)
fs.writeFile('../FileWrite/座右铭.txt', '\r\n云墨书生', {flag: 'a'}, err => {
if(err) {
console.log('写入失败')
return
}
console.log('写入成功')
})
1-4.createWriteStream 流式写入
语法: fs.createWriteStream(path[, options])
参数说明:
- path:文件路径
- options:选项配置(
可选
)
返回值: Object
代码示例:
js
// 1.导入 fs 模块
const fs = require('fs')
// 2.创建写入流对象(参数为文件的路径)
const ws = fs.createWriteStream('./FileWrite/观书有感.txt')
// 3.写入(write)
ws.write('半亩方塘一鉴开,\r\n')
ws.write('天光云影共徘徊。\r\n')
ws.write('问渠那得清如许?\r\n')
ws.write('为有源头活水来。\r\n')
// 4.关闭通道(可加可不加)
ws.close()
程序打开一个文件是需要消耗资源的
,流式写入可以减少打开关闭文件的次数。流式写入方式适用于
大文件写入或者频繁写入
的场景,writeFile
适用于写入频率较低的场景
。
1-5.写入文件的场景
文件写入
在计算机中是一个非常常见的操作,下面的场景都用到了文件写入:
- 下载文件
- 安装软件
- 保存程序日志,如 Git
- 编辑器保存文件
- 视频录制
当
需要持久化保存数据
的时候,我们就应该想到文件写入
二、文件读取
文件读取顾名思义,就是通过程序从文件中取出其中的数据,我们可以使用如下几种方式:
方法 | 说明 |
---|---|
readFile | 异步读取 |
readFileSync | 同步读取 |
createReadStream | 流式读取 |
2-1.readFile 异步读取
语法: fs.readFile(path[, options], callback)
参数说明:
- path:文件路径
- options:选项配置
可选
- callback:回调函数
返回值: undefined
代码示例:
js
// 1.引入 fs 模块
const fs = require('fs')
// 2.异步读取(readFile)
fs.readFile('../FileWrite/观书有感.txt', (err, data) => {
if(err) {
console.log('读取失败')
return
}
// 读取到的内容 data 是一个 Buffer
console.log(data)
// 可以通过 toString 方法将 Buffer 转换为字符串
console.log(data.toString())
})
2-2.readFileSync 同步读取
语法: fs.readFileSync(path[, options])
参数说明:
- path:文件路径
- options:选项配置
可选
返回值: string | Buffer
代码示例:
js
// 1.引入 fs 模块
const fs = require('fs')
// 2.同步读取(readFileSync)------------ 与异步读取不同的是,它只需要接受一个参数(文件路径)即可
let data = fs.readFileSync('../FileWrite/观书有感.txt')
console.log(data.toString())
2-3.createReadStream 流式读取
语法: fs.createReadStream(path[, options])
参数说明:
- path:文件路径
- options:选项配置
可选
返回值: Object
代码示例:
js
// 1.引入 fs 模块
const fs = require('fs')
// 2.创建读取流对象(createReadStream,参数为'读取的文件路径')
const rs = fs.createReadStream('../资料/笑看风云.mp4')
// 3.绑定 data 事件,用来获取读取到的数据(chunk:块儿;大块儿)
rs.on('data', chunk => {
// 回调函数 chunk:当从文件当中读取出来一块数据之后,就会执行一次回调
// 可以通过 length 方法,来获取每次读取的数据大小
console.log(chunk.length) // 65536字节 => 64KB
})
// 4.end(内容读取完毕后触发)可选事件
rs.on('end', () => {
console.log('读取完成')
})
2-4.读取文件应用场景
- 电脑开机
- 程序运行
- 编辑器打开文件
- 查看图片
- 播放视频
- 播放音乐
- Git 查看日志
- 上传文件
- 查看聊天记录
三、文件移动与重命名
在 Node.js 中,我们可以使用 rename
或 renameSync
来移动或重命名 文件或文件夹
语法:
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath)
参数说明:
- oldPath:文件当前的路径
- newPath:文件新的路径
- callback:操作后的回调函数(
renameSync是没有该参数的
)
代码示例:
js
// 引入 fs 模块
const fs = require('fs')
// 对文件'座右铭.txt'进行重命名(rename)
fs.rename('./座右铭.txt', './论语.txt', err => {
if(err) {
console.log('重命名失败')
return
}
console.log('重命名成功')
})
// 对文件'test.txt'移动到[资料]文件夹中(renameSync -- 与 rename 相比,该方法只是少了回调函数)
fs.renameSync('./test.txt', '../资料/test.txt')
四、文件删除
在 Node.js 中,我们可以使用 unlink
或 unlinkSync
来删除文件
语法:
fs.unlink(path, callback)
fs.unlinkSync(path)
参数说明:
- path:文件路径
- callback:操作后的回调函数(
unlinkSync是没有该参数的
)
代码示例:
js
// 引入 fs 模块
const fs = require('fs')
// 调用 unlink 方法来删除'观书有感.txt'文件
fs.unlink('./观书有感.txt', err => {
if(err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
// 调用 unlinkSync 方法来删除'垃圾文件.txt'文件
fs.unlinkSync('./垃圾文件.txt')
// 补充:Node.js 在14.4版本中新增了一个方法 -- rm | rmSync
fs.rm('./论语.txt', err => {
if(err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
五、文件夹操作
借助 Node.js
的能力,我们可以对文件夹进行 创建
、读取
、删除
等操作
方法 | 说明 |
---|---|
mkdir / mkdirSync | 创建文件夹 |
readdir / readdirSync | 读取文件夹 |
rmdir / rmdirSync | 删除文件夹 |
5-1. mkdir 创建文件夹
在 Node.js 中,我们可以使用 mkdir
或 mkdirSync
来创建文件夹
语法:
fs.mkdir(path[, options], callback)
fs.mkdirSync(path[, options])
参数说明:
- path:文件夹路径
- options:选项配置(
可选
) - callback:操作后的回调函数(
mkdirSync是没有该参数的
)
代码示例:
js
// 1.导入 fs 模块
const fs = require('fs')
// 2.创建文件夹 mkdir(mk => make:制作;dir => directory:文件夹)
fs.mkdir('./html', err => {
if(err) {
console.log('创建失败')
return
}
console.log('创建成功')
})
// 2-2 递归创建(这就要使用到那个可选参数了)
// 配置 recursize 为 true
fs.mkdirSync('./a/b/c', {recursive: true})
5-2.readdir 读取文件夹
在 Node.js 中,我们可以使用 readdir
或 readdirSync
来读取文件夹
语法:
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
参数说明:
- path:文件夹路径
- options:选项配置(
可选
) - callback:操作后的回调函数(
readdirSync是没有该参数的
)
代码示例:
js
// 导入 fs 模块
const fs = require('fs')
// 异步读取文件夹 readdir(read:读取;dir => directory:文件夹)
fs.readdir('../../资料', (err, data) => {
if(err) {
console.log('读取失败')
return
}
console.log(data)
})
// 同步读取文件夹 readdirSync
let data = fs.readdirSync('./')
console.log(data)
5-3.rmdir 删除文件夹
在 Node.js 中,我们可以使用 rmdir
或 rmdirSync
来删除文件夹
语法:
fs.rmdir(path[, options], callback)
fs.rmdirSync(path[, options])
参数说明:
- path:文件夹路径
- options:选项配置(
可选
) - callback:操作后的回调函数(
rmdirSync是没有该参数的
)
代码示例:
js
// 导入 fs 模块
const fs = require('fs')
// 异步删除文件夹 rmdir(rm => remove:移除;dir => directory:文件夹)
fs.rmdir('./html', err => {
if(err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
// 同步递归删除文件夹(不推荐使用)
fs.rmdirSync('./a', {recursive: true})
// 推荐使用 rm | rmSync 进行删除
fs.rm('./a', {recursive: true}, err => {
if(err) {
console.log('删除失败')
return
}
console.log('删除成功')
})
六、查看资源状态
在 Node.js 中,我们可以使用 stat
或 statSync
来查看资源的详细信息
语法:
fs.stat(path[, options], callback)
fs.statSync(path[, options])
参数说明:
- path:文件夹路径
- options:选项配置(
可选
) - callback:操作后的回调函数(
statSync是没有该参数的
)
代码示例:
js
// 导入 fs 模块
const fs = require('fs')
// 查看资源状态 stat
fs.stat('../资料/笑看风云.mp4', (err, data) => {
if(err) {
console.log('查看失败')
return
}
console.log(data)
// 可以通过 isFile 方法判断是否是一个文件
console.log(data.isFile())
// 可以通过 isDirectory 方法判断是否是一个文件夹
console.log(data.isDirectory())
})
结果值对象结构:
- size:文件体积
- birthtime:创建时间
- mtime:最后修改时间
- isFile:检查是否为文件
- isDirectory:检查是否为文件夹
- ...
七、相对路径问题
fs 模块对资源进行操作时,路径的写法有两种:
- 相对路径
./座右铭.txt
当前目录下的座右铭.txt座右铭.txt
等效于上面的写法../座右铭.txt
当前目录的上一级目录中的座右铭.txt
- 绝对路径
D:/index.html
Windows 系统下的绝对路径/index.html
Linux 系统下的绝对路径
相对路径中所谓的
当前目录
,指的是命令行的工作目录
,而并非是文件的所在目录所以当命令行的工作目录与文件所在目录不一致时,会出现一些 BUG
八、__dirname
__dirname
与 require
类似,都是 Node.js
环境中的'全局'变量
__dirname
保存着 当前文件所在目录的绝对路径
,可以使用 __dirname
与文件名拼接成绝对路径
代码示例:
js
const fs = require('fs')
fs.writeFileSync(__dirname + '/index.html', 'love')
使用 fs 模块的时候,尽量使用 __dirname 将路径转化为绝对路径,这样可以避免相对路径产生的 Bug。
九、练习
-
编写一个 JS 文件,实现文件复制的功能
js/** * 需求: * 复制『资料』文件夹下的『笑看风云.mp4』 */ const fs = require('fs') // process 是 nodeJs 中的模块(可以通过 process 中的一个方法来获得代码运行的内存占用量) const process = require('process') // 方式一:非流式操作 // 1.读取文件内容 let data = fs.readFileSync('../资料/笑看风云.mp4') // 2.写入文件 fs.writeFileSync('../资料/笑看风云-2.mp4', data) console.log(process.memoryUsage()) // rss = 114704384字节 => 109MB // 方式二:流式操作(方法二很更好一些,所占的资源会更少一些) // 1.创建读取流对象 const rs = fs.createReadStream('../资料/笑看风云.mp4') // 2.创建写入流对象 const ws = fs.createWriteStream('../资料/笑看风云-3.mp4') // 3.绑定 data 事件 rs.on('data', chunk => { ws.write(chunk) }) // 另一种写法(pipe 指的是'管道') // rs.pipe(ws) rs.on('end', () => { console.log(process.memoryUsage()) // rss = 53514240字节 => 51MB }) // 通过对两种方法代码运行的内存占用量进行对比,可以看出方法二所占的资源会更少一些
-
对一个文件夹中的所有文件进行重命名(要求:重命名后的文件名中个位数的前面加'0')
js// 导入 fs 模块 const fs = require('fs') // 读取 code 文件夹 const files = fs.readdirSync('./code') // 遍历数组 files.forEach(item => { // 拆分文件名 let data = item.split('.') // 解构赋值 let [num, name, suffix] = data let fileName = name + '.' + suffix // 判断:如果 num 小于10,就代表是一个一位数;并且其长度不大于2(防止重复运行代码后,导致无限加0) if(Number(num) < 10 && num.length < 2) { num = '0' + num } // 创建新的文件名 let newName = num + '.' + fileName // 重命名 fs.renameSync(`./code/${item}`, `./code/${newName}`) })
-
排序重命名(要求:少了一个文件,需要剩余的文件都按照顺序进行重新排序)
js// 导入 fs 模块 const fs = require('fs') // 读取 code 文件夹 const files = fs.readdirSync('./code') // 遍历数组 files.forEach((item, index) => { // 拆分 let [num, name, suffix] = item.split('.') let fileName = name + '.' + suffix // 自增 index++ // 判断 index 是否大于10 if(index < 10) { // 判断 num 是否与 index 相等,如果相等,就继续使用 num;反之,则使用 index num = Number(num) == index ? num : '0' + index }else { // 如果 index 大于等于10,就直接替换 num = index } // 创建新的文件名 let newName = num + '.' + fileName // 排序重命名 fs.renameSync(`./code/${item}`, `./code/${newName}`) })