















Buffer 是一个类似于数组的对象 ,用于表示固定长度的字节序列
Buffer 本质是一段内存空间,专门用来处理 二进制数据 。


上面说了Buffer大小固定却无法调整,目前学习了之后确实不知道该怎么理解,可以这样理解吗?Buffer一旦创建之后,就无法重新赋值,但是里面的元素可以改变。
Buffer可以直接对计算机内存进行操作。从第一章的学习来看,好像没有进行什么有价值的操作,也许在后面的学习中会学到,到时候可以返回来记录一下。
Node.js 中创建 Buffer 的方式主要如下几种:
xxxxxxxxxx21//创建了一个长度为 10 字节的 Buffer,相当于申请了 10 字节的内存空间,每个字节的值为 02let buf_1 = Buffer.alloc(10); // 结果为 <Buffer 00 00 00 00 00 00 00 00 00 00>使用alloc方法创建Buffer,会对每一个二进制位进行归零操作。
xxxxxxxxxx21//创建了一个长度为 10 字节的 Buffer,buffer 中可能存在旧的数据, 可能会影响执行结果,所以叫unsafe2let buf_2 = Buffer.allocUnsafe(10);使用allocUnsafe方法创建Buffer,不会对二进制位进行归零操作,如果一段二进制位是之前的程序使用的,那么会有旧的内存数据存在。
问题:既然allocUnsafe不安全,为什么不直接使用alloc方法呢?因为allocUnsafe方法创建Buffer快一些,在没有安全方面顾虑的时候,可以使用。
xxxxxxxxxx51//通过字符串创建 Buffer2let buf_3 = Buffer.from('hello');34//通过数组创建 Buffer5let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);


上面讲了从字符串转为Buffer,下面讲从Buffer转为字符串。
我们可以借助toString方法将 Buffer 转为字符串
xxxxxxxxxx21let buf_4 = Buffer.from([105, 108, 111, 118, 101, 121, 111, 117]);2console.log(buf_4.toString());// 输出 iloveyoutoString() 默认是按照
utf-8编码方式进行转换的。
Buffer 可以直接通过[]的方式对数据进行处理。
xxxxxxxxxx71let buf_3 = Buffer.from("hello")2//读取3console.log(buf_3[1]);4//修改5buf_3[1] = 97;6//查看字符串结果7console.log(buf_3.toString());输出结果:

注意:
- 如果修改的数值超过
255,则超过 8 位数据会被舍弃。为什么?因为一个字节占8个二进制位,那么一个字节可以表示的数值是2^8=256种可能。- 一个
utf-8的字符 一般 占 3 个字节
计算机基本组成


程序运行的基本流程




进程与线程










如果任务管理器没有显示pid,可以在菜单栏上→右键→选择pid,就可以显示了。
fs 全称为file system,称之为文件系统,是Node.js中的内置模块,可以对计算机中的磁盘进行操作。

不要小瞧了fs模块,前端项目,特别是桌面端的应用,和系统打交道特别多。在之前的计算机基础中已经说了,程序的启动是需要先读取文件的,这时候就是fs模块发挥作用了,不是我有限的想象中的,仅仅限于用户上传文件、下载文件、打开文件这些操作。
vscode是electron写的,但是底层用到的还是nodejs的方法。比如说:打开文件、保存文件、创建文件、文件移动和重命名、文件删除等等,就是使用fs模块。说明再复杂的软件,都是由一个个基础功能堆起来的。
本章节会介绍如下几个操作:
文件写入就是将数据 保存到文件 中,我们可以使用如下几个方法来实现该效果。
| 方法 | 说明 |
|---|---|
| writeFile | 异步写入 |
| writeFileSync | 同步写入 |
| appendFile / appendFileSync | 追加写入 |
| createWriteStream | 流式写入 |
语法: fs.writeFile(file, data[, options], callback)
参数说明:
[,options],表示options是可选参数,如果options参数不传,那么前面的逗号也不要写。)返回值: undefined
代码示例:
xxxxxxxxxx121// require 是 Node.js 环境中的'全局'变量,用来导入模块2const fs = require('fs');34//将 『三人行,必有我师焉。』 写入到当前文件夹下的『座右铭.txt』文件中5fs.writeFile('./座右铭.txt', '三人行,必有我师焉。', err => {6 //如果写入失败,则回调函数调用时,会传入错误对象;如写入成功,会传入 null7 if(err){8 console.log(err);9 return;10 }11 console.log('写入成功');12});语法: fs.writeFileSync(file, data[, options])
参数与 fs.writeFile 大体一致,只是没有 callback 参数
返回值: undefined
代码示例:
xxxxxxxxxx61// 注意:同步api的错误需要用 try...catch 来捕获。2try{3 fs.writeFileSync('./座右铭.txt', '三人行,必有我师焉。');4}catch(e){5 console.log(e);6}Node.js 中的磁盘操作是由其他线程完成的,结果的处理有两种模式:
- 同步处理: JavaScript 主线程会等待其他线程的执行结果,然后再继续执行主线程的代码,效率较低
- 异步处理: JavaScript 主线程不会等待其他线程的执行结果,直接执行后续的主线程代码,等到其他线程有执行结果之后,再插入到执行队列中等待被执行。效率较好
这里补充一下Node的一个重要知识点,是我在《深入浅出nodejs》中看到的:
在P71中,作者讲了Node的异常处理难点,因为nodejs中大部分API都是异步的,那么如果有2个异步API,(假设为A和B),我要确保A执行没有问题之后才能执行B,那么传统的方式都是在A、B执行的时候,外面嵌套一层try...catch,那么假设A执行时有错误了,try...catch捕获到了,但是B怎么接收到A的执行错误呢?
所以nodejs在处理异常上形成了一种约定,将异常作为回调函数的第一个实参传回,如果为空值,则表明异步调用没有异常抛出。
所以我看到的大部分nodejs的API,它们的回调函数,第一个参数都是err。
1-3. appendFile / appendFileSync 追加写入
appendFile 作用是在文件尾部追加内容,appendFile 语法与 writeFile 语法完全相同
语法:
fs.appendFile(file, data[, options], callback)
fs.appendFileSync(file, data[, options])
返回值: 二者都为 undefined
实例代码:
xxxxxxxxxx61fs.appendFile('./座右铭.txt','择其善者而从之,其不善者而改之。', err => {2 if(err) throw err;3 console.log('追加成功')4});56fs.appendFileSync('./座右铭.txt','\r\n温故而知新, 可以为师矣');语法: fs.createWriteStream(path[, options])
参数说明:
返回值: Object
代码示例:
xxxxxxxxxx131const fs = require("fs")23// 创建写入流对象4let ws = fs.createWriteStream('./观书有感.txt');56// 使用写入流对象的write()方法来写入7ws.write('半亩方塘一鉴开\r\n');8ws.write('天光云影共徘徊\r\n');9ws.write('问渠那得清如许\r\n');10ws.write('为有源头活水来\r\n');1112// 关闭写入流通道13ws.end();程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。
流式写入方式适用于 大文件写入或者频繁写入 的场景,
writeFile适合于 写入频率较低的场景
整个教程的场景介绍,只是说某些api可以做什么,供参考。
文件写入 在计算机中是一个非常常见的操作,下面的场景都用到了文件写入。
当 需要持久化保存数据 的时候,应该想到 文件写入
文件读取顾名思义,就是通过程序从文件中取出其中的数据,我们可以使用如下几种方式:
| 方法 | 说明 |
|---|---|
| readFile | 异步读取 |
| readFileSync | 同步读取 |
| createReadStream | 流式读取 |
语法: fs.readFile(path[, options], callback)
参数说明:
返回值: undefined
代码示例:
xxxxxxxxxx161//导入 fs 模块2const fs = require('fs');34fs.readFile('./座右铭.txt', (err, data) => {5 // 如果读取失败,err返回一个对象;如果成功,则是null6 if(err) throw err;7 // 如果读取失败,data返回一个undefined;如果成功,则是具体内容。8 // 这里没有设置options,所以返回的是一个Buffer对象。9 console.log(data);10});1112// 这里设置了options,这里是简写,如果写完整应该是这样:{encoding:"utf-8"}13fs.readFile('./座右铭.txt', 'utf-8',(err, data) => {14 if(err) throw err;15 console.log(data);16});语法: fs.readFileSync(path[, options])
参数说明:
返回值: string | Buffer
代码示例:
xxxxxxxxxx21let data = fs.readFileSync('./座右铭.txt');2let data2 = fs.readFileSync('./座右铭.txt', 'utf-8');语法:fs.createReadStream(path[, options])
参数说明:
返回值: Object
代码示例:
xxxxxxxxxx151const fs = require("fs");2// 创建读取流对象3let rs = fs.createReadStream('./观书有感.txt');456// rs绑定data事件7rs.on('data', chunk => {// 每次取出 64k 数据后执行一次 data 回调。8 console.log(chunk);// 参数chunk,单词本身有块的意思。当然这个参数名可以随便取。9 console.log(chunk.length);10});1112// rs绑定end事件,读取完毕后, 执行 end 回调。----可选事件13rs.on('end', () => {14 console.log('读取完成')15})重点注意:
这里的 rs.on 这个on事件是怎么来的???还有里面的参数"data"和"end",是固定套路吗?
我之前搜索过答案,说是Nodejs的events模块,但是具体的我还不懂,特别是文档我不知道该怎么找,可以先在视频下方问一下老师。
2024-08-05
这个还是通过ChatGPT4来解答了,解答的非常好:
问:这里面的on函数是什么?
答:
在 Node.js 中,
on函数是用于绑定事件监听器的方法,它是基于事件驱动编程模型的一部分。具体来说,on函数用于监听指定事件,并在事件发生时执行相应的回调函数。在你的代码中,
on函数用于监听读取流 (Readable Stream) 的data和end事件。以下是详细的解释:1.
data事件xxxxxxxxxx41rs.on('data', chunk => {2console.log(chunk);3console.log(chunk.length);4});
- 事件名称:
'data'- 描述: 每当有一块数据从流中读取出来时,
data事件就会被触发。默认情况下,每块数据的大小是 64KB。- 回调参数:
chunk,表示读取到的数据块。- 回调功能: 打印数据块的内容和长度。
2.
end事件xxxxxxxxxx31rs.on('end', () => {2console.log('读取完成');3});
- 事件名称:
'end'- 描述: 当所有数据都被读取完毕时,
end事件会被触发。- 回调参数: 无。
- 回调功能: 打印“读取完成”的信息。
on函数的定义
on函数是EventEmitter类的方法,Readable Stream是EventEmitter的一个实例。它的定义如下:xxxxxxxxxx11emitter.on(eventName, listener)
eventName: 字符串,表示事件的名称。listener: 函数,当事件触发时会调用该函数。使用场景
在 Node.js 中,许多对象都是事件发射器,比如
fs.createReadStream返回的流对象。通过on函数,你可以很方便地处理异步事件,如文件读取、网络请求、用户输入等。例子总结
结合你的代码,
on函数绑定了两个事件监听器,一个监听data事件,用于处理读取到的数据块;另一个监听end事件,用于处理流读取完成的情况。这使得你的程序可以异步、高效地处理文件读取操作。xxxxxxxxxx151const fs = require("fs");23// 创建读取流对象4let rs = fs.createReadStream('./观书有感.txt');56// rs绑定data事件7rs.on('data', chunk => {8console.log(chunk);9console.log(chunk.length);10});1112// rs绑定end事件,读取完毕后, 执行 end 回调13rs.on('end', () => {14console.log('读取完成');15});问(这是我特别不理解的地方,也是文档中找不到的地方):可是我在nodejs官方文档里面并没有查到fs.createReadStream的返回值可以使用on函数绑定事件?
答:
你遇到的困惑是因为
fs.createReadStream返回的并不是一个普通对象,而是一个Readable Stream对象,而Readable Stream继承自EventEmitter,所以它可以使用on函数来绑定事件。
fs.createReadStream的返回值在 Node.js 的官方文档中,
fs.createReadStream函数的返回值是一个fs.ReadStream对象。这个对象本质上是一个Readable Stream,而Readable Stream继承了EventEmitter类,因此它可以使用on函数来监听和处理事件。
事件驱动模型
Node.js 的核心是事件驱动的异步编程模型。
EventEmitter是这个模型的基础,许多核心模块(如流、HTTP 服务器、文件系统操作等)都继承自EventEmitter,以便支持事件监听和触发。代码示例
让我们通过代码示例和文档链接来更清晰地理解这一点。
xxxxxxxxxx151const fs = require("fs");23// 创建读取流对象4let rs = fs.createReadStream('./观书有感.txt');56// rs绑定data事件7rs.on('data', chunk => {8console.log(chunk);9console.log(chunk.length);10});1112// rs绑定end事件,读取完毕后, 执行 end 回调13rs.on('end', () => {14console.log('读取完成');15});在上面的代码中,
rs是一个fs.ReadStream对象,它继承自Readable Stream,因此它有on方法。文档参考
- EventEmitter 文档: Node.js EventEmitter
- Stream 文档: Node.js Stream
- fs.createReadStream 文档: Node.js fs.createReadStream
在
fs模块的文档中,fs.createReadStream部分会说明它返回一个ReadStream对象。进一步查看Stream模块的文档,你会发现ReadStream继承自Readable Stream,而Readable Stream继承自EventEmitter,这就解释了为什么fs.createReadStream返回的对象可以使用on方法。通过这些文档和代码示例,可以更好地理解 Node.js 中的事件驱动模型以及
fs.createReadStream返回值的行为。那我就查看stream里面的readable stream的文档,应该是这个:
里面详细说明了on可以绑定哪些事件,真的是解决了我的一大疑问。
练习:
复制资料文件夹下的“笑看风云.mp4“。
分析:现在没有学到复制、粘贴的api,但是前面学习了读取和写入的api,就这样完成。
xxxxxxxxxx151// 方式一:使用readFile writeFile2// 异步方法3const fs = require("fs");45fs.readFile("./笑看风云.mp4", (err, data) => {6 if (err) throw err;7 fs.writeFile("./笑看风云1.mp4", data, (err) => {8 if (err) throw err;9 console.log("复制成功");10 });11});1213// 同步方法14const data = fs.readFileSync("./笑看风云.mp4");15fs.writeFileSync("./笑看风云2.mp4", data);xxxxxxxxxx171// 方式二:使用流式操作2const fs = require("fs");34// 创建流式读取对象5const rs = fs.createReadStream("./笑看风云.mp4");6// 创建流式写入对象7const ws = fs.createWriteStream("./笑看风云3.mp4");89// 绑定data事件,读取一点就写入一点。10rs.on("data", (chunk) => {11 ws.write(chunk);12});1314// 读取完成触发,这里不是复制完成,但是时间相差不大,所以提示一下。15rs.on("end", () => {16 console.log("复制完成");17});
哪种方式好一些?
用流式操作好一些。为什么?因为readFile和writeFile是整读、整写,这个mp4文件是77.8MB,那么在操作时就需要占用77.8MB的内存。
但流式操作,理想状态下,是每次读取64KB的内容,然后写入,那么占用内存就只需要64KB。为什么说理想状态下是占用64KB内存呢?因为读取操作是读到内存中,而写入是写入硬盘中,读到内存中比写到硬盘中要快的多,所以可能没有写入完成,就已经读取了,但这并不会造成问题。为什么?因为读取和写入是不同的线程,只要读取的顺序是对的,那么写入的顺序就是对的。
可以使用process模块的memoryUsage()方法,来查看两种方式使用的真实内存情况。
xxxxxxxxxx51const process = require("process");23const data = fs.readFileSync("./mydb.sql");4fs.writeFileSync("./mydb2.sql", data);5console.log(process.memoryUsage());// 看rss这个属性,比较大小。xxxxxxxxxx61const process = require("process");23rs.on("end", () => {4console.log(process.memoryUsage());// 看rss这个属性,比较大小。5console.log("复制完成");6});
可以看到,当文件很大的时候,流式操作就有明显的优势了,但是文件较小时(我测试的文件大小为几十MB时),就差不多。为什么呢?不是说流式操作理想情况下占的内存是64KB吗?怎么文件较小时就差不多了。因为内存读取文件的速度比文件写入硬盘的速度快太多了,造成读取的内容堆在了内存中。
流式操作还有一种简单方法:
xxxxxxxxxx81const fs = require("fs");23// 创建流式读取对象4const rs = fs.createReadStream("./mydb.sql");5// 创建流式写入对象6const ws = fs.createWriteStream("./mydb3.sql");78rs.pipe(ws); // 使用pipe()方法,可以了解一下pipe方法官方文档:https://nodejs.cn/api/v20/stream.html#readablepipedestination-options
在 Node.js 中,我们可以使用 rename或 renameSync 来移动或重命名 文件或文件夹
语法:
fs.rename(oldPath, newPath, callback)
fs.renameSync(oldPath, newPath)
参数说明:
代码示例:
xxxxxxxxxx81// 第二个参数里面的directory文件夹必须存在,否则会报错 no such file or directory。23fs.rename('./观书有感.txt', './论语/观书有感.txt', (err) =>{4 if(err) throw err;5 console.log('移动完成')6});78fs.renameSync('./座右铭.txt', './论语/我的座右铭.txt');在 Node.js 中,我们可以使用 unlink 或 unlinkSync 来删除文件
语法:
fs.unlink(path, callback)
fs.unlinkSync(path)
参数说明:
代码示例:
xxxxxxxxxx81const fs = require('fs');23fs.unlink('./test.txt', err => {4 if(err) throw err;5 console.log('删除成功');6});78fs.unlinkSync('./test2.txt')补充:node@14.4新增了删除方法,fs.rm(path,callback)和fs.rmSync(path)。
借助 Node.js 的能力,我们可以对文件夹进行 创建 、 读取 、 删除 等操作。
| 方法 | 说明 |
|---|---|
| mkdir / mkdirSync | 创建文件夹 |
| readdir / readdirSync | 读取文件夹 |
| rmdir / rmdirSync | 删除文件夹 |
在 Node.js 中,我们可以使用 mkdir或 mkdirSync来创建文件夹
语法:
fs.mkdir(path[, options], callback)
fs.mkdirSync(path[, options])
参数说明:
示例代码:
xxxxxxxxxx141//异步创建文件夹,这里的path意思是在当前文件夹下创建page文件夹2fs.mkdir('./page', err => {3 if(err) throw err;4 console.log('创建成功');5});67//递归异步创建8fs.mkdir('./1/2/3', {recursive: true}, err => {9 if(err) throw err;10 console.log('递归创建成功');11});1213//递归同步创建文件夹14fs.mkdirSync('./x/y/z', {recursive: true});
在 Node.js 中,我们可以使用 readdir 或 readdirSync 来读取文件夹
语法:
fs.readdir(path[, options], callback)
fs.readdirSync(path[, options])
参数说明:
示例代码:
xxxxxxxxxx51//异步读取,读取文件所在文件夹的内容2fs.readdir('./', (err, data) => {3 if(err) throw err;4 console.log(data);// 返回结果是一个数组,数组元素是文件夹里面资源的名称。5});
xxxxxxxxxx71// 异步读取,读取文件所在盘符内的文件夹内容23// 这里是为了说明 path 为 / 的时候表示什么意思。在Windows系统中表示:这段代码所在文件,所处的是哪个盘,比如说这里就是 e:4fs.readdir("/",(err,data)=>{5 if(err) throw err6 console.log(data);7})
xxxxxxxxxx31//同步读取2let data = fs.readdirSync('./论语');3console.log(data);在 Node.js 中,我们可以使用 rmdir 或 rmdirSync 来删除文件夹
语法:
fs.rmdir(path[, options], callback)
fs.rmdirSync(path[, options])
参数说明:
示例代码:
xxxxxxxxxx171//异步删除文件夹2fs.rmdir('./page', err => {3 if(err) throw err;4 console.log('删除成功');5});67//异步递归删除文件夹8fs.rmdir('./1', {recursive: true}, err => {9 if(err) {10 console.log(err);11 return;12 }13 console.log('递归删除')14});1516//同步递归删除文件夹17fs.rmdirSync('./x', {recursive: true})提示:现在运行
fs.rmdir和fs.rmdirSync异步递归删除文件夹的方法会提示DeprecationWarning,建议使用fs.rm或fs.rmSync来递归删除。xxxxxxxxxx41fs.rm("./a",{recursive:true},err => {2if(err) throw err3console.log("删除成功")4})
在 Node.js 中,我们可以使用 stat 或 statSync 来查看资源的详细信息
语法:
fs.stat(path[, options], callback)
fs.statSync(path[, options])
参数说明:
示例代码:
xxxxxxxxxx91//异步获取状态2fs.stat('./data.txt', (err, data) => {3 if(err) throw err;4 console.log(data);5 // 如果获取成功,那么data身上有两个方法,data.isFile()查看是否为文件,data.isDirectory()查看是否为文件夹。6});78//同步获取状态9let data = fs.statSync('./data.txt');结果值对象结构:
fs 模块对资源进行操作时,路径的写法有两种:
相对路径
./座右铭.txt 当前目录下的座右铭.txt座右铭.txt 等效于上面的写法../座右铭.txt 当前目录的上一级目录中的座右铭.txt绝对路径
D:/ProgramFiles windows 系统下的绝对路径/usr/bin Linux 系统下的绝对路径相对路径中所谓的
当前目录,指的是命令行的工作目录,而并非是文件的所在目录。也就是执行时的工作目录可能与文件的所在目录不一致,那么写相对路径就可能造成问题。(虽然我每次都会注意命令行所在的目录,但写了相对路径,程序的鲁棒性还是不够好,有造成Bug的隐患。)所以当命令行的工作目录与文件所在目录不一致时,会出现一些 BUG。
怎么解决呢?使用绝对路径,用到下面的
__dirname。
__dirname 与 require 类似,都是 Node.js 环境中的'全局'变量,无需引入可以直接使用。
__dirname 保存着 当前文件所在目录的绝对路径 ,可以使用 __dirname 与文件名拼接成绝对路径。
代码示例:
xxxxxxxxxx21let data = fs.readFileSync(__dirname + '/data.txt');2console.log(data);使用 fs 模块的时候,尽量使用 __dirname 将路径转化为绝对路径,这样可以避免相对路径产生的Bug。
注意:
__dirname返回的结果,最后面不带有/,所以如果是直接拼接字符串,则需要在具体文件或文件夹名前面加上/。但如果是使用path.resolve()来拼接,则不需要在具体文件或文件夹名前面加上/,这个方法会帮助我们处理好的,如果加上了,就会形成E://a.txt这样的形式,程序也能识别、也不会报错,但最好不要这样。
1、文件重命名,将文件夹中文件名1到9前面加上0。

xxxxxxxxxx201// 将test里面的文件,1至9开头的,前面添加 023const fs = require("fs");45// 获取文件夹里面文件的详情。6let data = fs.readdirSync("./test");78// 遍历里面的文件9data.forEach((item) => {10 // 解构赋值的方法要经常使用11 let [pre, name] = item.split("-");1213 // 如果数字小于1014 if (Number(pre) < 10) {15 pre = "0" + pre;16 let newPath = pre + "-" + name;17 // 这里使用了同步的方法,因为没有别的事情需要做,什么时候同步、什么时候异步,要看实际需求。18 fs.renameSync(`./test/${item}`, `./test/${newPath}`);19 }20});2、需求:将test2里面的文件,1至9开头的,前面添加 0。但是缺少2开头的,需要从3开头,将数字减1,让数字能够连续。
分析:需要数字连续,所以数字大于9的文件名也要改。

xxxxxxxxxx141const fs = require("fs");23const data = fs.readdirSync("./test2");45data.forEach((item) => {6 let [pre, name] = item.split("-");7 if (Number(pre) < 10) {8 pre = "0" + (Number(pre) > 1 ? Number(pre) - 1 : pre);9 fs.renameSync(`./test2/${item}`, `./test2/${pre}-${name}`);10 } else {11 pre = Number(pre) - 1 > 9 ? Number(pre) - 1 : "0" + (Number(pre) - 1);12 fs.renameSync(`./test2/${item}`, `./test2/${pre}-${name}`);13 }14});
这个模块老师只是展示了一下API的使用。
path 模块提供了 操作路径 的功能,我们将介绍如下几个较为常用的几个 API:
| API | 说明 |
|---|---|
| path.resolve | 拼接规范的绝对路径(常用) |
| path.sep | 获取操作系统的路径分隔符 |
| path.parse | 解析路径并返回对象 |
| path.basename | 获取路径的基础名称 |
| path.dirname | 获取路径的目录名 |
| path.extname | 获取路径的扩展名 |
代码示例:
xxxxxxxxxx201const path = require('path');23//拼接绝对路径,这里的test应该是一个文件夹,如果是文件,需要带上文件名后缀。4console.log(path.resolve(__dirname, 'test'));56//获取路径分隔符7console.log(path.sep);89//解析路径10let pathname = 'D:/program file/nodejs/node.exe';11console.log(path.parse(pathname));1213//获取路径基础名称14console.log(path.basename(pathname))1516//获取路径的目录名17console.log(path.dirname(pathname));1819//获取路径的扩展名20console.log(path.extname(pathname));执行结果如下:

从结果可以看到,不需要都记住,只需要记住path.resolve()来拼接路径,以及path.parse()解析路径即可,解析结果是一个对象,里面什么都有。
补充:
__filename和require、__dirname一样,都是“全局”变量。
__filename返回当前文件的绝对路径。