fs文件系统模块
fs文件系统模块
以下为学习过程中的极简提炼笔记,以供重温巩固学习
学习准备
准备工作
完成AJAX原理
学习目的
fs文件系统模块
fs模块定义:file system,意为文件系统;也可以把它称之为是 fs API
作用:可以跟我们的硬盘进行交互,比如,比如说可以实现文件的创建、删除、重命名、移动等操作,还有可以完成文件内容的写入和读取,以及文件夹的相关操作
fs写入文件
需求:新建一个文件,文件名叫做座右铭.txt,并且往这个文件当中写入一段内容。写入什么内容?三人行,则必有我师焉
步骤:
导入 FS 模块,通过
const fs = reqire('fs')
语法来导入- 声明一个变量接收,可以使用const,也可以使用var,也可以使用let,都可以
- fs,它是一个变量的名称,这个名称你可以自定义,只要满足标识符的要求就可以,绝大多数情况我们都会把它命名为 fs,为了语义更准确
- require,它是一个全局的函数,可以用来导入模块,不能乱写(见AJAX中,CommonJS标准导入)
- 'fs',所引入的模块的名称,不能乱写
通过fs.whiteFile(file,data,[options],callback)方法写入,接收4个参数
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
- 文件如果不存在,会帮我们自动创建文件并写入)
- data:待写入的数据,要往文件里边写入什么内容
- optios:选项设置(可选的选项配置对象,暂时略)
- callback:写入回调函数
- 回调函数它什么时候执行?当写入在完成之后,就会自动去调用这个回调函数,并且会把错误传递给咱这个函数,你也可以认为是传递给这个error
- 如果写入失败,那么 error 它的值就是一个错误对象。
- 如果写入成功, error 值就是一个null。
- 当然这个形参名字你可以随便写, 不一定非要写 error ,写 abc 也是可以的。
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
意义:通过脚本,实现文件自动化写入
实际应用案例:
- vscode 也是借助于 nodejs 能力开发出来的,虽然它是借助election框架;而这个 electron 它是借助于node 搭建起来的,那么 vscode 在写入文件时也是借助了 node 的 fs 模块实现的文件写入
// require 是 Node.js 环境中的'全局'变量,用来导入模块
const fs = require('fs');
//将 『三人行,必有我师焉。』写入到当前文件夹下的『座右铭.txt』文件中
fs.writeFile('./座右铭.txt','三人行,必有我师焉',err =>{
//如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入nu11
if(err){
console.log(err);
console.log('写入失败');
return;
}
console.log('写入成功');
})
node 文件写入.js
- 效果:脚本目录下新建了一个 座右铭.txt,并已写入 三人行,必有我师焉
fs同步与异步
需求:理解同步与异步区别
运行逻辑:
- 如上节的案例,writeFile()这个方法就是一个异步的工作模式,代码自上而下开始运行,走到 whiteFile 这一块儿,它要进行磁盘的写入,而此时它会将这个磁盘写入操作交给另另外一个线程去完成。
- 也就是说现在我们有两个线程,第一个线程是 js 的主线程来执行解析 js 代码。第二个是我们的磁盘的写入,这样一个线程,我们把这一列线程统称为是 io 线程,输入和输出线程
- 然后我们在启动这个线程之后, whiteFile 这个方法有一个特点,就是它是异步的,异步是不会等待这个结果回来的,它会直接向后去运行后边代码。
- 而这个 io 线程在写入完毕之后,它会将这个回调函数,大家可以看一下这个回调函数,然后压入到任务队列当中。
- 与定时器是非常非常像,它会把这个回调函数执行这个任务压到队列当中,等 js 主线程,它再把这些初始化的代码执行完毕之后,然后就会从任务队列当中把这个回调函数取出来,然后再执行
概念:*.js脚本运行时占用一个线程,文件写入磁盘,占用另一个线程,称为I/O输入输出线程
同步写入:
导入 FS 模块,通过
const fs = reqire('fs')
语法来导入- 声明一个变量接收,可以使用const,也可以使用var,也可以使用let,都可以
- fs,它是一个变量的名称,这个名称你可以自定义,只要满足标识符的要求就可以,绝大多数情况我们都会把它命名为 fs,为了语义更准确
- require,它是一个全局的函数,可以用来导入模块,不能乱写(见AJAX中,CommonJS标准导入)
- 'fs',所引入的模块的名称,不能乱写
通过fs.whiteFileSync(file,data,[options])方法写入,接收3个参数,没有回调函数
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
- 文件如果不存在,会帮我们自动创建文件并写入)
- data:待写入的数据,要往文件里边写入什么内容
- optios:选项设置(可选的选项配置对象,暂时略)
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
工作模式:调用fs.whiteFileSync()方法,js进程会等io进程跑完了再往下跑
意义:
- 异步效率更高
- 同步好理解,按顺序执行,api好用
const fs = require('fs');
fs.writeFile('./座右铭.txt','三人行,必有我师焉',err =>{
//如果写入失败,则回调函数调用时,会传入错误对象,如写入成功,会传入nu11
if(err){
console.log('写入失败');
return;
}
console.log('写入成功');
})
console.log(1+1);
// 实际上,会先打印出1+1的结果后,再出上面的写入结果
const fs = require('fs');
fs.writeFileSync('./data.txt','test')
fs追加写入
需求:往文件追加写入
运行逻辑:
- 概念:appendFile作用是在文件尾部追加内容,appendFile语法与writeFile语法完全相同
步骤:
- 导入 FS 模块,通过
const fs = reqire('fs')
语法来导入- 声明一个变量接收,可以使用const,也可以使用var,也可以使用let,都可以
- fs,它是一个变量的名称,这个名称你可以自定义,只要满足标识符的要求就可以,绝大多数情况我们都会把它命名为 fs,为了语义更准确
- require,它是一个全局的函数,可以用来导入模块,不能乱写(见AJAX中,CommonJS标准导入)
- 'fs',所引入的模块的名称,不能乱写
- 通过fs.appendFile(file,data,[options],callback)方法异步追加写入,接收4个参数
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
- 文件如果不存在,会帮我们自动创建文件并写入)
- data:待写入的数据,要往文件里边写入什么内容
- optios:选项设置(可选的选项配置对象,暂时略)
- callback:写入回调函数
- 回调函数它什么时候执行?当写入在完成之后,就会自动去调用这个回调函数,并且会把错误传递给咱这个函数,你也可以认为是传递给这个error
- 如果写入失败,那么 error 它的值就是一个错误对象。
- 如果写入成功, error 值就是一个null。
- 当然这个形参名字你可以随便写, 不一定非要写 error ,写 abc 也是可以的。
- file:写入标的,要写入的文件名,要往哪个文件里面去写内容
- 通过fs.appendFileSync(file,data,[options])方法,同步写入
- 参数同上,除了没有回调函数
- 在fs模块中,换行需要使用\r\n(即使用转义字符,类似markdown的解析)
- 导入 FS 模块,通过
应用场景:
- 在需要持续地往文件写入内容的场景,如各种日志
- 网站访问,希望记录用户的访问时间和相关信息
const fs = require('fs');
// 异步
fs.appendFile('./座右铭.txt','择其善者而从之,其不善者而改之。',err => {
// 判断
if(err) {
console.log('写入失败');
return;
}
console.log('追加写入成功');
});
// 同步
fs.appendFileSync('./座右铭.txt','\r\n温故而知新,可以为师矣');
通过writeFile加配置对象{flag:'a'},也能实现追加写入效果
const fs = require('fs');
// 异步
fs.writeFile('./座右铭.txt','666666',{flag:'a'},err => {
// 判断
if(err) {
console.log('写入失败');
return;
}
console.log('追加写入成功');
});
文件流式写入
需求:打算写一首诗,这个诗的名字叫做观书有感,然后我们把这个诗的内容写到观书有感.txt 这个文件当中。
运行逻辑:
- 概念:通过createWriteStream()方法实现
步骤:
- 导入 FS 模块,通过
const fs = reqire('fs')
语法来导入- 声明一个变量接收,可以使用const,也可以使用var,也可以使用let,都可以
- fs,它是一个变量的名称,这个名称你可以自定义,只要满足标识符的要求就可以,绝大多数情况我们都会把它命名为 fs,为了语义更准确
- require,它是一个全局的函数,可以用来导入模块,不能乱写(见AJAX中,CommonJS标准导入)
- 'fs',所引入的模块的名称,不能乱写
- 创建一个写入流对象
const ws = fs.createWriteStream()
- const 名字的话可以随便写,这里我把名字定义为 ws 等于一个 fs.createWriteStream
- create 单词的本意是创建的意思,而 write 单词的本意是写入的意思。 stream 单词的本意是流的意思
- createWriteStream('文件路径')方法接收一个参数,这个参数就是文件的路径;
- 这个操作相当于声明一个与文件建立通道的变量,什么时候想写,就往变量传入内容即可
- 后续通过write()方法,往变量写入
- 最后通过close()方法结束写入并保存。
- 注:
- 当脚本在执行完毕之后,资源也会被回收,通道也因此会被断开,而这个内容也已经写入完毕了,所以说这个 close 我们加也可以,不加也是 OK 的
- 为了语义明确,肯定加
- 导入 FS 模块,通过
应用场景:
- 这种createWriteStream()写入方式与 writeFile 区别:
- createWriteStream()更适合于写入频次较高的场景
- createWriteStream()也适合大文件的写入
- writeFile()是一次性的,写入完毕后就断开连接了,更适合写入频次相对较少的场景
- 这种createWriteStream()写入方式与 writeFile 区别:
const fs = require('fs');
const ws = fs.createWriteStream('./观书有感.txt');
ws.write('半亩方塘一鉴开\r\n');
ws.write('天光云影共徘徊\r\n');
ws.write('问渠那得清如许\r\n');
ws.write('为有源头活水来\r\n');
ws.close();
文件写入应用场景
哪些场景用到文件写入:
- 下载文件、视频
- 安装软件
- 写入程序日志,如 git log
- 编辑器保存文件,如ctrl+s
- 视频录制
场景总结:
- 当需要持久化的保存数据时,应该要想到文件写入
方法 | 说明 |
---|---|
writeFile() | 异步写入;可通过配置{flag:'a'} 实现同步写入 |
writeFileSync() | 同步写入 |
createWriteStream() + write() + close() | 流式写入 |
文件读取
- 运行逻辑:
- 概念:通过3个方法实现,分别是:readFile()和readFileSync()和createreadStream()
方法 | 说明 |
---|---|
readFile() | 异步读取 |
readFileSync() | 同步读取 |
createreadStream() | 流式读取 |
需求:有一个观书有感.txt,这是我们之前已经写好的文件内容了。我们打算通过 4-文件读取.js 这个脚本去读取观书有感.txt 的文件内容,并且在控制台里边儿做一个输出
步骤:
- 导入 FS 模块,通过
const fs = reqire('fs')
语法来导入 - 调用引入的 FS 模块中的 readfile() 方法
- 在调用时接收三个参数,有两个是必填的,一个是可填的
- 文件路径,必填
- 配置对象,可选参数(用不到它,所以先不给它传参)
- 回调函数,必填
- 第一个参数是文件路径,我们要读的文件是 观书有感.txt。好,
- 然后下边儿回调函数,这个回调函数我需要单独说一下,它有两个形参,当然了两个形参名字你可以随便写,你这写a,这写 b 都没有问题。
- 等他读取到文件内容之后,这个回调函数会被执行,并且会传两个值进来。这个 error 它用来接收错误的信息,这个 data 用来接收读取的文件内容。
- 这个 error 的情形其实跟我们之前写入文件那个是一样的,所以我们可以做一个判断,如果说要是一个错误对象,那我们就做一个输出,对不起,读取失败,然后我们写一个return。
- 那么其次,如果 error 要是为null,表明它已经读取成功,我们就可以打印一下读取它的文件内容。
- 另外一种读取方式,就是同步读取, let data = fs.readFileSync(),它接收一个参数就行了,就是文件的路径,如'let data = fs.readFileSync('./观书有感.txt');'
- 导入 FS 模块,通过
意义:通过脚本,实现文件自动化读取
//1.引入 fs 模块
const fs = require('fs');
//2.异步读取
fs.readFile('./观书有感.txt',(err,data)=>{
if(err){
console.log('读取失败~~');
return;
}
console.log(data);
// 控制台打印:是一个buffer
console.log(data.toString());
// 打印utf8中文
})
// 同步读取 + 转字符串
let data2 = fs.readFileSync('./观书有感.txt');
console.log(data2.toString());
node 文件读取.js
# 控制台打印:是一个buffer
# toString 控制台打印:打印utf8中文
文件读取应用场景
哪些场景用到文件读取:
- 电脑开机,开机之后需要首先将磁盘里边的内容,先读取到内存当中,然后 CPU 才可以对程序去做一个运行
- 程序运行,比方说我想运行一下英雄联盟,双击之后,它里边的程序相关文件就会载入到内存当中,其实也就是从硬盘当中,在硬盘当中将那些文件数据全都读出来,然后载入到这个内存里边去
- 编辑器打开文件
- 查看图片
- 播放视频、音乐
- git 查看日志
- 上传文件
- 查看本地聊天记录
场景总结:
- 当需要加载数据时,应该要想到文件读取
文件流式读取
运行逻辑:
- 概念:通过createreadStream()方法实现
- 原理:硬盘 => 读取 => 内存 => 渲染/存储 => 硬盘
需求:将资料文件夹当中笑看风云.mp4这个文件把它读取出来,载入内存
步骤:
- 导入 FS 模块,通过
const fs = reqire('fs')
语法来导入- 声明一个变量接收,可以使用const,也可以使用var,也可以使用let,都可以
- fs,它是一个变量的名称,这个名称你可以自定义,只要满足标识符的要求就可以,绝大多数情况我们都会把它命名为 fs,为了语义更准确
- require,它是一个全局的函数,可以用来导入模块,不能乱写(见AJAX中,CommonJS标准导入)
- 'fs',所引入的模块的名称,不能乱写
- 创建流式读取对象
const rs = fs.createReadStream()
- const 名字的话可以随便写,这里我把名字定义为 rs 等于一个 fs.createReadStream
- create 单词的本意是创建的意思,而 read 单词的本意是读取的意思。 stream 单词的本意是流的意思
- createWriteStream('文件路径')方法接收一个参数,这个参数就是文件的路径,接收的路径操作同命令行操作;
- 用 on() 方法,为读取流对象,绑定一个 data 事件,用来获取读取到的数据;
- 如
rs.on('data',chunk =>{})
,第一个参数,即事件的名字叫data;第二个参数,是一个回调函数,有一个形参,名字叫chunk,当然这个名字可以随便写,官方是把这个名字起成了chunk,单词本身有块,有大块儿的意思
- 运行逻辑:
- 当从文件当中读取出来一块数据之后,就会执行一次回调。
- 流式读取就是一块一块的读,我先读一块,我再读一块,而这个回调函数是每当读完一块之后,就会执行这个回调函数,
- 并且会把读取到的内容传递给这个形参,让他去执行,让他去处理。
- 可以打印形参,发现是读取到的16进制数据;可以通过 length 属性,来获得这个 buffer 的长度,显示为65536,单位是字节,即每次从文件当中读取的,是64kb数据
- toString无效,因为文件是MP4编码的,视频编码无法转字符
- 读取完毕后,绑定end事件结束
- 导入 FS 模块,通过
应用场景:
- 这种createReadStream()读取方式作用:
- createWriteStream()在读取大文件或者处理大文件的时候,它可以提高整体的效率
- 这种createReadStream()读取方式作用:
// 引入
const fs = require('fs');
//2.创建读取流对象
constrs= fs.createReadstream('../资料/笑看风云.mp4');
//3.绑定 data事件 chunk 块儿 大块儿
rs.on('data',chunk =>{
console.log(chunk.length);//65536字节=>64KB
//console.log(chunk.tostring());//65536字节=>64KB
});
//4.end 可选事件
rs.on('end',()=>{
console.log('读取完成');
});
文件复制
需求:复制一下资料文件夹当中的笑看风云.mp4 这个文件
方式一:使用readFileSync()和writeFileSync()同步读写
const fs = require('fs');
//方式一 readFile 读取文件内容
Let data = fs.readFilesync('../资料/笑看风云.mp4');
// 写入文件
fs.writeFileSync('../资料/笑看风云-2.mp4',data);
// 导入process模块查看内存占用
const process= require('process');
console.log(process.memoryUsage());//rss 110710784字节
- 方式二:使用流式操作createreadStream()和createWriteStream()以及write()方法,也是要读,读完之后再写
//方式二 流式操作
//创建读取流对象
const rs= fs.createReadstream('../资料/笑看风云.mp4');
//创建写入流对象
const ws = fs.createWritestream('../资料/笑看风云-3.mp4');
//绑定 data 事件
rs.on('data', chunk =>{
ws.write(chunk);
})
// 导入process模块查看内存占用,并且要等执行完再统计
const process= require('process');
rs.on('end',() =>{
console.log(process.memoryUsage());//43106304
})
两种写法比较:
- 第二种方式(流式操作)它会更好一些,它所占的资源会更少一些
- 原因:
- 为什么呢?咱们来捋一捋这个思路,你看咱先说第一种方式,它是把这个文件的所有内容全部都读到了内存当中,然后再把这个数据写到文件里边。那这个文件多大?这个文件 70 多兆,大家可以看一下 77. 8 兆,也就是说它至少要占据 77. 8 兆的内存空间。
- 然后但是我们来看看第二种方式,是流式的读取与写入,这种方式的话它的理想状态。注意我说的是理想状态,它只需要 64 kb 的内存空间就可以完成文件的赋值,因为它每次它只取64,然他往这个文件里边去写,取一点写一点,所以说他理想状态下只要有 64 KB 的内存空间就可以完成这个复制。
- 那为什么说它是一个理想状态是 64 k b,这是因为我们的读取速度一般都会比写入速度要更快,所以它把数据读取过来之后往里边写,还没等他写完第二块数据就读进来了,所以就会形成这么一个局面,这里换一个方式给大家来演示。
- 比方说我们打算往这个文件里边去复制(左边图示文件复制到右边文件),那么这种读取流的方式就是它读一点儿,然后写一点儿,读一点,写一点,然后读一点写一点。当然这是一种理想状态,它只占这 64 KB 的空间,但是我们说了它这个读取速度一般都要比这个写入速度要快,虽然等这个还没写完,另外一个就过来了(内存读入了多块),他这个去写入这个读,然后这个读这个读,是吧?这个写,所以理想情况下是 64 kb,但是即使是这样子,它所占的内存空间也比整个文件的内存空间要小。
- 可通过导入process模块,即
const process=require('process')
,这个 process 也是 nodeJS 的一个内置模块,可以通过它里边儿的一个方法来获得代码运行时的内存占用量。 - 注意,两种方式比较时,流式操作下,应通过rs.on(end)等把这个文件都读完之后,再去统计这个脚本它总共消耗的内存的这个资源
方式三:简便操作,rs 读取流,直接调这个 pipe 括弧里边儿跟一个ws传参,用这种方式也可以快速实现这个复制
//创建读取流对象
const rs= fs.createReadstream('../资料/笑看风云.mp4');
//创建写入流对象
const ws = fs.createWritestream('../资料/笑看风云-3.mp4');
rs.pipe(ws);
读取流,把这个数据读取完之后交给写入流,交给写入流,这个 pipe 单词的本意是管道的意思,管道就是我这儿把东西取出来,通过管道传递给你,这个写入流是这么一个意思。当然了,这个内容的话,我们用的并不是特别多,所以大家以后看到这个代码知道是什么意思就可以了。
文件重命名和移动
在 Node.js 中,我们可以使用 rename 或 renameSync 来移动或重命名文件或文件夹。
- rename三个参数(参数1要修改的文件路径(如案例中写的相对路径),参数2修改后的新路径,第三个是回调函数,形参是err)
- 本质是一样的都是更改文件的路径,脚本意义在于自动化操作
- renameSync两个参数,没有后面的回调函数
// 导入fs模块
const fs = require('fs');
// 调用rename 或 renameSync方法
fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{
if(err) throw err;
console.log('移动完成')
});
fs.renameSync('./座右铭.txt', './论语/我的座右铭.txt');
node .\文件重命名与移动.js
文件删除
在 Node.js 中,我们可以使用 unlink 或 unlinkSync 来删除文件。
unlink两个参数,第一个是文件路径,第二个是回调
unlinkSync没有回调
Node.js 14.4中,还有一个rm方法,参数与unlink一样
unlink和rm,都有同步的方法,rmSync
// 导入fs模块
const fs = require('fs');
// 调用unlink 或 unlinkSync方法
fs.unlink('./data.txt', err => {
if(err) throw err;
console.log('删除成功');
});
fs.unlinkSync('./data1.txt');
// 调用rm方法
fs.rm('./data.txt', err => {
if(err) throw err;
console.log('删除成功');
});
fs.rmSync('./data1.txt');
文件夹操作
方法 | 说明 |
---|---|
mkdir/mkdirSync | 创建文件夹 |
readdir/readdirSync | 读取文件夹 |
rmdir/rmdirSync | 删除文件夹 |
mkdir 创建文件夹 在 Node.js 中,我们可以使用 mkdir 或 mkdirSync 来创建文件夹。
mk为make制作的缩写
dir为directory文件夹缩写
方法接收三个参数(参数1文件夹配置路径,参数2配置对象是可选参数,参数3回调函数)
- fs.mkdir(path[, options], callback)
- fs.mkdirSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置(可选)
- callback 操作后的回调
注意:
- 递归创建需要加第二个配置对象,recursive:true
// 导入fs模块
const fs = require('fs');
//异步创建文件夹
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 读取文件夹
参数说明:
- path 文件夹路径
- options 选项配置(
可选
) - callback 操作后的回调
- 有两个参数,参数1是err错误信息,参数2是读取到的文件夹内容,可得到对应文件夹内的资源名称列表
// 导入fs模块
const fs = require('fs');
//异步读取
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])
后续版本的node.js将会使用
fs.rm
取代fs.rmdir
参数说明:
- path 文件夹路径
- options 选项配置(
可选
)- 配置
{ recursive: true }
对象,实现递归删除
- 配置
- callback 操作后的回调
// 导入fs模块
const fs = require('fs');
//异步删除文件夹
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 })
查看资源状态
在 Node.js 中,我们可以使用 stat
或 statSync
来查看资源的详细信息
status状态的单词缩写
语法:
fs.stat(path[, options], callback)
fs.statSync(path[, options])
参数说明:
- path 文件夹路径
- options 选项配置(
可选
) - callback 操作后的回调
- 参数1,错误对象
- 参数2,文件的状态信息,也是一个对象
示例代码:
// 导入fs模块
const fs = require('fs');
//异步获取状态
fs.stat('./data.txt', (err, data) => {
if (err) throw err;
console.log(data);
});
// 通过 isFile 获取文件状态,返回true,则表明是一个文件
console.log(data.isFile());
// 通过 isDirectory 方法,检测目标资源是不是一个文件夹
//同步获取状态
let data = fs.statSync('./data.txt');
- 结果值对象结构:
- size 文件体积
- birthtime 创建时间
- atime 最后访问时间
- mtime 最后修改时间
- ctime 最后1次修改文件状态的时间
- isFile 检测是否为文件
- isDirectory 检测是否为文件夹
- ...
相对路径问题
fs 模块对资源进行操作时,路径的写法有两种:
相对路径
./座右铭.txt
当前目录下的座右铭.txt座右铭.txt
等效于上面的写法../座右铭.txt
当前目录的上一级目录中的座右铭.txt
绝对路径
D:/Program Files
windows 系统下的绝对路径,注意C盘的权限问题/usr/bin
Linux 系统下的绝对路径,斜线开头的路径,在windows 系统下使用的效果,同样能在盘符根目录下操作
相对路径中
当前目录
的定义,指的是当前命令行所在的工作目录
,参照物是命令行所在目录,而并非是文件的所在目录
所以当命令行的工作目录与文件所在目录不一致时,会出现一些 BUG
// 导入fs模块
const fs = require('fs');
// 相对路径
fs.whiteFileSync('./index.html','love')
fs.whiteFileSync('index.html','love')
fs.whiteFileSync('../index.html','love')
// 绝对路径
fs.whiteFileSync('D:/Program Files/index.html','love')
// linux
fs.whiteFileSync('/usr/bin/index.html','love')
// Windows下会在盘符根目录下创建
fs.whiteFileSync('/index.html','love')
__dirname
__dirname
与require
类似,都是 Node.js 环境中的'全局'变量__dirname
保存着所在文件的所在目录的绝对路径
,可以使用__dirname
与文件名拼接成绝对路径- 可以理解为,使用 fs 模块的时候,通过
__dirname + '/文件名.txt'
拼接操作,以获取文件最终的绝对路径 - 缺点:打印发现,路径的分割符不统一
代码示例:
let data = fs.readFileSync(__dirname + '/data.txt');
console.log(data);
使用 fs 模块的时候,尽量使用 __dirname 将路径转化为绝对路径,这样可以避免相对路径产生的 Bug
练习
/**
* 需求:
* 复制『资料』文件夹下的『笑看风云.mp4』
*/
const fs = require('fs');
const process = require('process');
//方式一 readFile
//读取文件内容
let data = fs.readFileSync('../资料/笑看风云.mp4');
//写入文件
fs.writeFileSync('../资料/笑看风云-2.mp4', data);
console.log(process.memoryUsage()); // rss 110710784 字节 105MB
// {rss: 121552896, heapTotal: 9015296, heapUsed: 7597008, external: 82478504, arrayBuffers: 81610072}
//方式二 流式操作
//创建读取流对象
const rs = fs.createReadStream('../资料/笑看风云.mp4');
//创建写入流对象
const ws = fs.createWriteStream('../资料/笑看风云-3.mp4');
//绑定 data 事件
rs.on('data', chunk => {
ws.write(chunk);
});
rs.on('end', () => {
console.log(process.memoryUsage()); // 43106304 => 41M
// {rss: 58126336, heapTotal: 12423168, heapUsed: 8682752, external: 12617116, arrayBuffers: 11748696}
});
// 方式三 通过管道的方式实现文件复制
rs.pipe(ws);
//导入 fs 模块
const fs = require('fs');
//读取 code 文件夹
const files = fs.readdirSync('./code');
//遍历数组
files.forEach(item => {
// 查看数组中的每个元素
console.log(item)
//拆分文件名,以文件名中的‘-’符号作拆分
let data = item.split('-');
// 查看拆分后的结果
console.log(data)
// 声明变量解构赋值
let [num, name] = data; //解构赋值
// 查看解构后结果
console.log(num, name)
//判断
if (Number(num) < 10) {
num = '0' + num;
}
//创建新的文件名
let newName = num + '-' + name;
//重命名,第一个参数,旧路径+旧名字,第二个参数新路径+新名字
fs.renameSync(`./code/${item}`, `./code/${newName}`);
});
//导入 fs 模块
const fs = require('fs');
//读取 code 文件夹
const files = fs.readdirSync('./code');
//遍历数组
files.forEach((item, index) => {
//拆分
let [num, name] = item.split('-');
//index 自增
index++;
//判断
index = index < 10 ? '0' + index : index;
//拼接新的名字
let newName = index + '-' + name;
//移动文件
fs.renameSync(`./code/${item}`, `./code/${newName}`);
});
path模块
path 模块提供了 操作路径
的功能,我们将介绍如下几个较为常用的几个 API:
API | 说明 |
---|---|
path.resolve | 拼接规范的绝对路径 常用 |
path.sep | 获取操作系统的路径分隔符 |
path.parse | 解析路径并返回对象,获取路径的相关信息 |
path.basename | 获取路径的基础名称 |
path.dirname | 获取路径的目录名 |
path.extname | 获得路径的扩展名 |
- 拼接后的路径分割符,都是反斜线/,是规范的绝对路径
- 拼接时可以不写相对路径前面的./
- 拼接时不能将相对路径前面写成/,否则变为了绝对路径,拼接时则变为从这个绝对路径开始,拼接后面的相对路径,没用上__dirname
- 通常使用path.resolve时,第一个路径传入绝对路径,后面的多个参数传相对路径
__dirname
: 当前文件所在目录的绝对路径__filename
: 当前文件的绝对路径- windows获取的分割符 \
- Linux获取的分割符是反斜线 /
- 转义字符,两个斜线
\\
反义成反斜线/ - 反斜线
/
:东北<--->西南 - 斜线
\
:西北<--->东南
const path = require('path');
//获取路径分隔符
console.log(path.sep);
//通过path.resolve,拼接规范的绝对路径,通过使用时,在参数1传入绝对路径,参数2传入相对路径
console.log(path.resolve(__dirname, 'test'));
//解析路径
let pathname = 'D:/program file/nodejs/node.exe';
console.log(path.parse(pathname));
//获取路径基础名称
console.log(path.basename(pathname))
//获取路径的目录名
console.log(path.dirname(pathname));
//获取路径的扩展名
console.log(path.extname(pathname));
__dirname
: 当前文件所在目录的绝对路径__filename
: 当前文件的绝对路径
//导入 fs
const fs = require('fs');
// 导入 path
const path = require('path');
// 写入文件
// fs.writeFileSync(__dirname + '/index.html', 'love');
// console.log(__dirname + '/index.html');
// 打印发现,路径的分割符不统一
// resolve 拼接绝对路径
// console.log(path.resolve(__dirname, './index.html'));
// 拼接时可以不写相对路径前面的./
// console.log(path.resolve(__dirname, 'index.html'));
// 拼接时不能将相对路径前面写成/,否则变为了绝对路径
// console.log(path.resolve(__dirname, '/index.html', './test'));
// sep 分隔符,separate的缩写
// 获取路径分隔符
console.log(path.sep); // windows获取的分割符 \ Linux获取的分割符 /
// parse 方法 __dirname '全局变量'
// console.log(__filename); // 文件的绝对路径
// 解析路径
// 转义字符,两个斜线\\反义成反斜线/
let str = 'D:\\nodeJS\\13-path\\代码\\path.js';
// console.log(path.parse(str));
// basename获取路径基础名称
// console.log(path.basename(str));
// dirname获取路径的目录名
// console.log(path.dirname(str));
// extname获取路径的扩展名
// console.log(path.extname(str));