fs模块
file system(文件系统)
,简称fs,可以实现与硬盘的数据交互。
本章会介绍以下几个操作:
- 文件写
- 文件读
- 文件移动与重命名
- 文件删除
- 文件夹操作
- 查看资源状态
在实现上述功能时,需要首先调用fs
模块
const fs = require('fs')
文件写出
writeFile/writeFileSync方法
-
最常见的fs模块写方法:writeFile和writeFileSync;
-
这两个方法的返回值都是:
undefined
1.writeFile异步模型
writeFile方法就是异步的,主线程不会等待输入任务执行结束,会先运行后面的代码。
-
语法:
fs.writeFile(file,data[,options],callback)
参数说明:
- file 输出的文件名(可带路径)
- data 待输出的数据
- options 选项设置,flag=w
- callback 回调函数,当输出任务结束后执行回调函数;
回调函数有一个参数,err,如果发生错误系统就会返回这个参数
// 举例 fs.writeFile('./座右铭.txt','三人行,必有我师焉',err =>{ if(err){ // 发生错误 console.log('写入失败') }else{ // 不发生错误 console.log('写入成功') } }
异步输出执行过程
-
JS有个主线程,当执行到writeFile时,会把I/O任务交给另外一个IO线程;
主线程不会等待输出任务的完成,而是去继续执行其他任务;
-
当IO任务完成后,IO线程会将回调函数压入任务队列中;
-
等JS主线程执行完所有代码之后,就会去任务队列中取出回调函数执行任务。
2.writeFileSync同步模型
主线程遇到writeFileSync输出任务时,等待IO任务完成,才会执行其他工作。
-
语法:
fs.writeFileSync(file, data[, options])
没有回调函数;
返回值:
undefined
注意
- 以上两种参数的写入方式都会清空原信息后,再写入。
- 返回值均为
undefined
追加写
-
追加写入会在原来内容的后面添加新的内容,而不会清空原内容。
-
什么时候追加写入?
- 需要不断持续的向文件内写入信息,如日志文件、记录用户登录网站信息的文件。
1.appendFile异步追加写
- 语法:
fs.appendFile(file, data[, options], callback)
2.appendFileSync同步追加写
- 语法:
fs.appendFileSync(file, data[, options])
3.writeFile实现追加写
-
语法:
fs.writeFile(name,data,{flag:'a'},callback)
添加了第三个参数选项。
注意
- appendFile和appednFileSync的返回值 也是undefined
createWriteStream流式写
-
为什么需要流失写入?和writeFile方法的区别是什么?
-
writeFile方法开始执行会打开一个文件,完成写入任务之后就会关闭文件。
每遇到一个wirteFile方法就需要打开、关闭一个文件。
-
流失写入需要手动开启和关闭文件。
不断的写入文件,只需要打开和关闭文件一次,在打开和关闭之间可以不断使用write写入非常方便。
-
-
流失写入和wirteFile的常用场景
程序开启和关闭一个文件是非常消耗资源的,流失写入可以减少打开和关闭的次数。
- 流式写入适用于大文件写入或者频繁写入的场景
- writeFile更适合写入频率比较低的场景
-
语法:
fs.createWriteStream(path[, options])
参数说明:
- path 文件路径
- options 选项配置( 可选)
- 返回值:
Object
抽象的文件流对象,需要操作这个对象的wirte方法写入内容。
// 1.导入js文件 const fs = require('fs') // 2.创建写入流对象,开启通道 const ws = fs.createWriteStream('./观书有感.txt') // 3.写入内容 write ws.write('半亩方塘一鉴开\n') ws.write('天光云影共徘徊\n') ws.write('问渠那得清如许\n') ws.write('为有源头活水来\n') // 4.关闭通道 ws.close()
注意:
- 开启通道,会清空该写入流对象里的旧内容。
- 各个write之间是追加写入,后面的内容不会覆盖前面的。
文件读取
文件读取,就是程序从文件中取出数据,可以使用以下几种方法
readFile/readFileSync方法
1.readFile
异步读取方法。
-
语法:
fs.readFile(path[, options], callback)
参数:
- path 文件路径
- options 选项配置
- callback 回调函数: 回调函数有两个参数,第一个参数err是发生的异常,如果不发生异常为空;第二个参数data是读取到的数据
返回值:
undefined
// 导入 fs 模块
const fs = require('fs');
// 读取数据
fs.readFile('./座右铭.txt', (err, data) => {
if(err) throw err;
console.log(data);
})
// 读取数据,指定为utf-8编码
fs.readFile('./座右铭.txt', 'utf-8',(err, data) => {
if(err) throw err;
console.log(data);
});
2.readFileSync
同步读取方法。
-
语法:
fs.readFileSync(path[, options])
参数说明:
- path 文件路径
- options 选项配置
返回值:
string | Buffer
(读取的数据存放在里面)
let data = fs.readFileSync('./座右铭.txt');
let data2 = fs.readFileSync('./座右铭.txt', 'utf-8');
流式读取
-
普通读取方法
一次读取全部数据到内存中
-
流式读取方法
把待读取的内容划分为一块块,按块读取;每次读取 65536字节64KB($2^{16}$)的数据。流式读取可以减少占用的内存,提高文件效率。
-
语法:
fs.createReadStream(path[, options])
参数:
- path 文件路径
- options 选项配置( 可选)
返回值:
Object
待读取文件的抽象对象。这步相当于打开了文件,需要对这个对象进行后续的读取操作才可以获得数据。
// 创建读取流对象
let rs = fs.createReadStream('./观书有感.txt');
// 每次取出 64k 数据后执行一次 data 回调
rs.on('data', data => {
console.log(data);
console.log(data.length);
});
// 读取完毕后, 执行 end 回调
rs.on('end', () => {
console.log('读取完成')
})
// data 读取完每一个块
// end 读取完成
文件移动与重命名
在 Node.js 中,可以使用 rename
或 renameSync
来移动或重命名文件或文件夹。
-
语法:
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath)
参数说明:
- oldPath 文件当前的路径
- newPath 文件新的路径
- callback 操作后的回调 一个err参数的回调
注意:第一个参数就旧路径;(和赋值的逻辑不同A=B,让B给A,这个是A到B)
-
示例
fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{ if(err) throw err; console.log('移动完成') }); fs.renameSync('./座右铭.txt', './论语/我的座右铭.txt');
文件删除
在 Node.js 中,使用 unlink
或 unlinkSync
来删除文件
-
语法:
fs.unlink(path, callback)
fs.unlinkSync(path)
参数说明:
- path 文件路径
- callback 操作后的回调:一个err参数的回调
-
举例
const fs = require('fs'); fs.unlink('./test.txt', err => { if(err) throw err; console.log('删除成功'); }); fs.unlinkSync('./test2.txt');
文件夹操作
mkdir创建文件夹
在 Node.js 中,可以使用 mkdir
或 mkdirSync
来创建文件夹
-
语法
fs.mkdir(path[, options], callback)
fs.mkdirSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置:
{recursive: true}
实现递归创建文件夹 - callback 操作后的回调 :和文件写出的操作函数一样
-
举例
```javascript // 当前目录创建page文件夹 fs.mkdir(‘./page’, err => { if(err) throw err; console.log(‘创建成功’); }) // 递归异步创建 fs.mkdir(‘./1/2/3’, {recursive: true}, err => { if(err) throw err; console.log(‘递归创建成功’); }) // 递归同步创建文件夹 fs.mkdirSync(‘./x/y/z’, {recursive: true})
readdir读取文件夹
在 Node.js 中,我们可以使用 readdir
或 readdirSync
来读取文件夹
-
语法
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置( 可选)
- callback 操作后的回调
-
代码
//异步读取 fs.readdir('./论语', (err, data) => { if(err) throw err; console.log(data); }); //同步读取 let data = fs.readdirSync('./论语'); console.log(data);
rmdir删除文件夹
在 Node.js 中,可以使用 rmdir
或 rmdirSync
来删除文件夹
-
语法
fs.rmdir(path[, options], callback)
fs.rmdirSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置( 可选)
{recursive: true}
递归删除文件夹 - callback 操作后的回调
-
示例代码
注意:如果待删除文件夹下有其他文件夹,需要使用递归删除,否则删除失败
```java //异步删除文件夹 fs.rmdir(‘./page’, err => { if(err) throw err; console.log(‘删除成功’); }); //异步递归删除文件夹 fs.rmdir(‘./1’, {recursive: true}, err => { if(err) { console.log(err); } console.log(‘递归删除’) }); //同步递归删除文件夹 fs.rmdirSync(‘./x’, {recursive: true})
建议使用rm删除文件夹
查看资源状态
在Node.js中,可以使用stat
或statSync
查看资源的详细信息。
-
语法:
fs.stat(path[, options], callback)
fs.statSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置 (可选)
- callback 操作后的回调,和文件读的回调函数参数类似,err和data。
-
举例
//异步获取状态
fs.stat('./data.txt', (err, data) => {
if(err) throw err;
console.log(data);
})
//同步获取状态
let data = fs.statSync('./data.txt');
结果值对象结构: size 文件体积 birthtime 创建时间 mtime 最后修改时间 isFile 检测是否为文件 isDirectory 检测是否为文件夹
相对路径的问题
fs模块对资源进行操作时,路径的写法有两种:
-
相对路径
-
当前目录下的file.txt文件,以下两种方法等价
./座右铭.txt
座右铭.txt
-
当前目录上一级目录的file.txt文件
../座右铭.txt
注意
相对路径中的
当前目录
,指的是命令行的工作目录
,而不是文件所在的目录所以当命令行的工作目录和文件所在的目录不一致时,会出现一些bug。解决方法见下一节
-
-
绝对路径
-
D:/xxx
windows系统下的绝对路径 -
/user/bin
Linux系统下的绝对路径
-
__dirname
-
__dirname
与require
类似,都是Node.js环境中的‘全局’变量 -
__dirname
保存当前文件所在目录的绝对路径
,经常使用__dirname与文件名拼接成绝对路径当前文件所在目录的绝对路径:理解为打开windows某个文件窗口,位于大白框的内容就是文件,位于上面地址栏的内容就是
当前文件所在目录的绝对路径。
let data = fs.readFileSync(__dirname + '/data.txt'); // 要拼接成绝对路径,所以前面写的是/。因为要保证拼接后的路径符合规范直接被识别。
console.log(data);
使用fs模块,尽量使用__dirname将路径转换为绝对路径,这样可以避免相对路径产生的bug