NodeJs内置模块

Tips:内置模块:下载NodeJs自带的模块,无需二次下载。

fs模块

文件操作都是基于fs模块。

操作文件

同步读取

readFileSync:同步读取(两个参数) 第二个参数可以是一个对象{encoding:’utf-8’};可以为字符串’utf-8’。有返回值,返回值为读取的内容。

1
2
3
4
5
6
7
//找不到 字符串 是 undefined ; 找不到 对象 是 null;
let fs = require("fs");
let result = fs.readFileSync("./文本ing.txt",{encoding:"utf-8"});
let results = fs.readFileSync("./文本ing.txt",'utf-8');
console.log(result);
console.log(results);
console.log("后续的代码!");

现象:由于是同步读取,会进行代码阻塞,先读取文本内容,最后输出”后续的代码!”。

异步读取

回调函数

readFile:异步读取(三个参数) 第三个参数是个回调函数,可以获取读取的错误与正确数据。没有返回值。

1
2
3
4
5
6
7
8
fs.readFile("./文本ing.txt",{encoding:"utf-8"},(err,data)=>{
if(err){
console.log(`读取文件错误${err}`);
return;
}
console.log(data);
})
console.log("后续的代码!");

现象:由于是异步读取,代码不会阻塞,先输出”后续的代码!”。

promise

promises.readFile:异步读取(两个参数),没有返回值。

1
2
3
4
5
6
fs.promises.readFile("./文本ing.txt",{encoding:"utf-8"}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(`读取文件错误${err}`)
})
console.log("后续的代码!");

现象:由于是异步读取,代码不会阻塞,先输出”后续的代码!”。

同步写入

writeFileSync(file,data, [options]):同步写入,文件写入的是字符串,所需需要JSON.stringify();写入操作 若文件名不存在,则自动创建

options是个对象,包含flag:写入的方式;encoding:字符编码方式;其中flag常用的几种配置如下:

  • r:只读;
  • w:写入(复写) (默认操作);
  • a:写入(追加写);
1
2
3
4
5
6
7
8
// 简单的文件的写入
const fs = require('fs');
const contents = {
name: "zs",
age: "20"
}
// 文件写入的是字符串,所需需要JSON.stringify(); 写入操作 若文件名不存在,则自动创建
fs.writeFileSync('./bb.txt',JSON.stringify(contents),{flag:"w",encoding:"utf-8"});

异步写入

writeFile(file,data,[options],callback):

1
2
3
4
5
6
7
8
const content = "hello world 异步写入ing~";
fs.writeFile('./bb.txt',content,{flag:"w",encoding:"utf-8"},(err)=>{
if(err){
console.log(err);
return;
}
console.log("写入成功");
});

操作文件夹

创建文件夹

使用fs.mkdir()或fs.mkdirSync()创建一个新文件夹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 同步方法 mkdirSync 
/**
* 内置一个或者两个参数
* 第一个参数必选 创建文件夹的路径和创建的名称
* 第二个参数可选 如果说没有第二个参数 那么只能创建一层目录
* 第二个参数是一个对象 对象是 {recursive : true} 即:是否递归创建
*/

// 一个参数
// const fs = require('fs');
// fs.mkdirSync('./ce/ee/ff'); //一个参数 因为没有ee,没有ee/ff 会报错

// 两个参数
const fs = require('fs');
fs.mkdirSync('./ce/ee/ff',{recursive:true}) //递归 创建成功了
1
2
3
4
5
6
7
8
9
// 异步方法 mkdir  与同步相比多了一个回调函数 
const fs = require("fs");
fs.mkdir("./ce/ee/ff", { recursive: true }, (err) => {
if (err) {
console.log(err);
return;
}
console.log("创建成功");
});

读取文件夹内容

使用fs.readdir()或fs.readdirSync()读取文件夹信息;这是查看一个文件夹中的所有文件夹或者文件,类似与doc命令中的dir;返回值是一个数组。

普通读取

得到一个数组,数组里面为字符串,但是不知道字符串中的具体信息(该字符串是文件夹还是文件);

1
2
3
4
5
6
// 同步方法 readdirSync : 查看文件夹信息  查看一个文件夹中的所有文件夹, 类似于doc中的dir;
// 内置一个参数=>路径
// 返回值是一个数组 查看的是文件夹的第一级的所有文件,第二级是么有的;
const fs = require('fs');
const result = fs.readdirSync("../文件夹读取内容");
console.log(result); // [ 'js同级目录1', 'js同级目录2', 'js同级目录3', 'read.js' ]
1
2
3
4
5
6
7
8
9
// 异步方法 readdir  
const fs = require("fs");
fs.readdir("../文件夹读取内容", (err, files) => {
if (err) {
console.log(err);
return;
}
console.log(files); // [ 'js同级目录1', 'js同级目录2', 'js同级目录3', 'read.js' ]
});
详细读取

普通读取相比,多了一个参数。得到一个数组,其中1代表文件;2代表文件夹。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fs = require("fs");
fs.readdir("../文件夹读取内容",{withFileTypes:true} ,(err, files) => {
if (err) {
console.log(err);
return;
}
console.log(files);
});
/**
* [
Dirent { name: 'js同级目录1', [Symbol(type)]: 2 },
Dirent { name: 'js同级目录2', [Symbol(type)]: 2 },
Dirent { name: 'js同级目录3', [Symbol(type)]: 2 },
Dirent { name: 'read.js', [Symbol(type)]: 1 }
]
*/

通过递归函数,获取每个文件的名字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const fs = require("fs");
const readDirectory = (path) => {
fs.readdir(path, { withFileTypes: true }, (err, files) => {
if (err) {
console.log(err);
return;
}
files.forEach((file) => {
// isDirectory() 判断是不是文件夹
if (file.isDirectory()) {
readDirectory(`${path}/${file.name}`);
} else {
console.log(file.name);
}
});
});
};

readDirectory("../文件夹读取内容");
/**
* read.js
* 1.1content.txt
* 2.2content.txt
*/

其他操作

  • statSync:查看文件夹或者目录信息;主要用到了其 isFile()方法来判断是否为文件;返回值是一个对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // 1.文件夹
    let fs = require('fs');
    let result = fs.statSync('./ce');
    console.log(result);

    /* 返回一个对象,这个文件夹的所有信息
    Stats {
    dev: 2658792828,
    mode: 16822,
    nlink: 1,
    uid: 0,
    gid: 0,
    rdev: 0,
    blksize: 4096,
    ino: 1688849860493693,
    size: 0,
    blocks: 0,
    atimeMs: 1645532058723.3967,
    mtimeMs: 1645532058722.3972,
    ctimeMs: 1645532058722.3972,
    birthtimeMs: 1645532035511.7517,
    atime: 2022-02-22T12:14:18.723Z,
    mtime: 2022-02-22T12:14:18.722Z,
    ctime: 2022-02-22T12:14:18.722Z,
    birthtime: 2022-02-22T12:13:55.512Z
    }
    */
    console.log(result.isFile()); //false =>因为是文件夹;

    // 2.文件
    let fs = require('fs');
    let result = fs.statSync('./ce/ce.txt');
    console.log(result); //和上面的一样,返回一个对象 这个文件的所有信息
    let isFile = result.isFile();
    console.log(isFile); // true =>这是个文件
  • rmdirSync:删除文件夹

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 语法和mkdir是一模一样的

    // 删除的是文件夹,不能删除文件

    // 一个参数
    // let fs = require('fs');
    // fs.rmdirSync('ce/ee') //出错,因为下面还有别的文件

    // 两个参数
    let fs = require('fs');
    // fs.rmdirSync('ce/ee',{recursive:true})
    fs.rmdirSync('ce/ce2',{recursive:true})
  • unlinkSync:删除文件

    1
    2
    3
    4
    5
    6
    // 删除文件

    // 一个参数,即删除文件的路径

    let fs = require('fs');
    fs.unlinkSync('./ce/ce.txt')
  • renameSync:修改文件名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 修改文件名
    /**
    * 不仅仅可以修改文件名和修改后缀 还可以进行移动 内置两个参数
    * 第一个参数是原来的文件路径 + 文件名
    * 第二个参数是移动和更名后的文件路径 + 文件名
    * */

    let fs = require('fs');
    fs.renameSync('./a.jpg',"./ce/ee/b.png");

events模块

Node中的核心API都是基于异步事件驱动的

  • 在这个体系中,某些对象(发射器(Emitters))发出某一个事件;
  • 我们可以监听这个事件(监听器 Listeners),并且传入的回调函数,这个回调函数会在监听到事件时调用;

发出事件和监听事件都是通过EventEmitter类来完成的,它们都属于events对象。

  • emitter.on(eventName, listener):监听事件,也可以使用addListener;
  • emitter.off(eventName, listener):移除事件监听,也可以使用removeListener;
  • emitter.emit(eventName[, …args]):发出事件,可以携带一些参数;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// events模块中的事件总线
const EventEmitter = require('events');

// 创建 EventEmitter 的实例
const emitter = new EventEmitter();

function fslFun(name,age){
console.log("this is emiter~~",name,age); // this is emiter~~ fsllala 18
}

// 监听事件
emitter.on('fsl', fslFun);

// 发射事件
emitter.emit('fsl', "fsllala",18);

// 取消事件
emitter.off("fsl",fslFun);

stream模块

http模块的Request和Response对象是基于流实现的;

  1. 什么是Stream(小溪、小河,在编程中通常翻译为流)呢?

    • 我们的第一反应应该是流水,源源不断的流动。
    • 程序中的流也是类似的含义,我们可以想象当我们从一个文件中读取数据时,文件的二进制(字节)数据会源源不断的被读取到我们程序中;
    • 而这个一连串的字节,就是我们程序中的流;

    所以,我们可以这样理解流:

    • 是连续字节的一种表现形式和抽象概念;
    • 流应该是可读的,也是可写的;
  2. 在之前学习文件的读写时,我们可以直接通过 readFile或者 writeFile方式读写文件,为什么还需要流呢?

    • 直接读写文件的方式,虽然简单,但是无法控制一些细节的操作;
    • 比如从什么位置开始读、读到什么位置、一次性读取多少个字节;
    • 读到某个位置后,暂停读取,某个时刻恢复继续读取等等;
    • 或者这个文件非常大,比如一个视频文件,一次性全部读取并不合适;
  3. Node.js中有四种基本流类型:

    • Writable:可以向其写入数据的流(例如 fs.createWriteStream());
    • Readable:可以从中读取数据的流(例如 fs.createReadStream());
    • Duplex:同时为Readable和Writable(例如 net.Socket);
    • Transform:Duplex可以在写入和读取数据时修改或转换数据的流(例如zlib.createDeflate());

Readable

可以从中读取数据的流(例如 fs.createReadStream());

  • 最基本用法:去读全部数据,此时和readFile()没区别;
1
2
3
4
5
6
7
8
const fs = require("fs");

const readStream = fs.createReadStream("./note.txt");

readStream.on("data", (chunk) => {
console.log(chunk.toString());
});
console.log(123);

现象:因为异步,所以先打印123,然后打印note.txt里面的内容(hello world 啦啦 stream流读取ing~~~);

  • 设置参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fs = require("fs");

/**
* start:文件读取开始的位置;
* end:文件读取结束的位置;
* highWaterMark:一次性读取字节的长度,默认是64kb;
*/
const readStream = fs.createReadStream("./note.txt",{
start:3,
end:10,
});

// 监听读取到的数据(数据有变化,就会触发)
readStream.on("data", (chunk) => {
console.log(chunk.toString()); // lo world
});
  • 设置暂停开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const fs = require("fs");


/**
* start:文件读取开始的位置;
* end:文件读取结束的位置;
* highWaterMark:一次性读取字节的长度,默认是64kb;
*/
const readStream = fs.createReadStream("./note.txt",{
start:3,
end:10,
highWaterMark:5
});

// 监听读取到的数据(数据有变化,就会触发)
readStream.on("data", (chunk) => {
console.log(chunk.toString());
readStream.pause(); // 暂停

setTimeout(() => {
readStream.resume(); // 开始
}, 2000);
});
  • 其他监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const fs = require("fs");

const readStream = fs.createReadStream("./note.txt",{
start:3,
end:10,
});

readStream.on("data", (chunk) => {
console.log(chunk.toString());
});


readStream.on("open",()=>{
console.log("读取的文件被打开~");
})
readStream.on("end",()=>{
console.log("读取的文件被结束~");
})
readStream.on("close",()=>{
console.log("文件被关闭~");
})

/**
* 读取的文件被打开~
* lo world
* 读取的文件被结束~
* 文件被关闭~
*/

Writable

可以向其写入数据的流(例如 fs.createWriteStream());

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const fs = require("fs");

// output.txt没有会被自动创建
const writer = fs.createWriteStream("./output.txt", {
encoding: "utf-8",
flags: "a",
})

const datas = "啦啦啦,这是需要写入的内容ing~";
writer.write(datas,err=>{
if(err){
console.log(err);
return;
}
console.log("文件写入成功!")
})
  • 监听其他事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const fs = require("fs");

// output.txt没有会被自动创建
const writer = fs.createWriteStream("./output.txt", {
encoding: "utf-8",
flags: "a",
})

const datas = "啦啦啦,这是需要写入的内容ing~";
writer.write(datas,err=>{
if(err){
console.log(err);
return;
}
console.log("文件写入成功!")
});


writer.on("open",()=>{
console.log("文件被打开")
})

/**
* close的监听
* 因为写入流在打开后是不会自动关闭的,所以我们并不能监听到 close 事件;
* 我们必须手动关闭,来告诉Node已经写入结束了;
*/
writer.on("close",()=>{
console.log("文件被关闭")
})
// 手动关闭
writer.close();
  • end();啥也不传,就是close();传了就是追加为末尾的字符串+close();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const fs = require("fs");

// output.txt没有会被自动创建
const writer = fs.createWriteStream("./output.txt", {
encoding: "utf-8",
flags: "a",
})

const datas = "啦啦啦,这是需要写入的内容ing~";
writer.write(datas,err=>{
if(err){
console.log(err);
return;
}
console.log("文件写入成功!")
});


writer.on("open",()=>{
console.log("文件被打开")
})

writer.on("close",()=>{
console.log("文件被关闭")
})

/**
* end方法:
* 操作1:将最后的内容写到文件中
* 操作2:关闭文件
*/
writer.end("lalala~~");

pipe

实现功能效果:将读取到的 输入流,手动的放到 输出流中进行写入。(复制粘贴操作);

  • 方式一:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const fs = require("fs");

const readStream = fs.createReadStream("./data.txt");
const writeStream = fs.createWriteStream("./data-copy.txt");


readStream.on("data", (chunk) => {
console.log(chunk.toString());
writeStream.write(chunk);
});

readStream.on("end", () => {
console.log("Done");
writeStream.end();
})

效果:读取data.txt,然后将其内容写入新建的文件data-copy.txt中;

  • 方式二:与上面代码等效;建立了一个管道,将读到的数据直接写入;
1
2
3
4
5
6
const fs = require("fs");

const readStream = fs.createReadStream("./data.txt");
const writeStream = fs.createWriteStream("./data-copy.txt");

readStream.pipe(writeStream);

全局

1
2
console.log(__filename);   //查看当前文件的绝对路径  精确到文件名 
console.log(__dirname); //查看当前文件的绝对路径 精确到文件夹名

url模块

  • 我们只使用其中的一个方法 目的是解析url;
  • 将一个完整的url解析成一个对象 使用url模块中的parse方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const url = require('url');
let str1 = "https://www.baidu.com:443/kang/index.html?name=Eric&age=18";
// 使用url模块中的parse方法进行处理url
// 返回值是一个对象 内置一个参数 参数是url
console.log(url.parse(str1));
/*
Url {
protocol: 'https:',
host: 'www.baidu.com:443',
port: '443',
hostname: 'www.baidu.com',
search: '?name=Eric&age=18',
query: 'name=Eric&age=18',
pathname: '/kang/index.html',
path: '/kang/index.html?name=Eric&age=18',
href: 'https://www.baidu.com:443/kang/index.html?name=Eric&age=18'
}
*/

querystring模块

  • 这个模块也是只有一个作用:用来处理get参数的;
  • 因为我们直接获取到的get参数是一个字符串 不能使用 name=Mary&age=19;
  • 我们可以借助querystring模块进行处理 使用模块中parse方法进行处理;
  • 将字符串格式的get参数 name=Mary&age=19 转化成对象格式 { name: ‘Mary’, age: ‘19’ }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const url = require('url');
const qs = require("querystring");

let str1 = "https://www.baidu.com:443/kang/index.html?name=Eric&age=18";
// 解析url地址 解析成为对象
let urlObj = url.parse(str1);
// 获取url对象中的get参数 存储在对象中的query属性中
let params = urlObj.query; // name=Mary&age=19
// 使用querystring模块中的方法 将参数name=Mary&age=19解析成为对象
let result = qs.parse(params);
console.log(result); //{ name: 'Eric', age: '18' }
let {name,age}=result;
console.log(name);//Eric
console.log(age);//18

path模块

node version: v16.18.0 (之前好像path.resolve()拼接好像没有盘符)

将两个路径拼接起来;看起来很简单,其实有坑:不同系统的路径分隔符可能不一样。

1
2
3
4
5
6
7
8
9
10
11
const basePath = "/user/why";
const filename = "abc.txt";

//将上面的路径拼接起来
/**
* 下面这样是不行的:
* 因为不同系统的路径分隔符可能不一样
* Linux/mac os 拼接符 /
* window拼接符 / \ \\
*/
const path= basePath +"/"+filename;

使用 path.join(xx,xx);进行拼接;

1
2
3
4
5
6
7
8
const path = require("path");
const basePath = "/user/why";
const filename = "abc.txt";

//将上面的路径拼接起来

const filePath= path.join(basePath,filename);
console.log(filePath); // \user\why\abc.txt (上面的basePath的拼接符会根据不同系统自动转化的)

path模块也是针对路径的模块 记住这些方法

  • basename:获取路径的最后一部分
  • dirname:获取除了页面部分
  • extname:获取后缀名
  • parse:获取一个对象 对象上述的所有
  • join:连接路径 相对路径
  • resolve:连接路径 绝对路径
1
2
3
4
5
6
const path =require("path");

// 传递若干参数 把所有的参数当成路径进行连接
// path.resolve() 绝对路径;
console.log(__dirname); //查看当前文件的绝对路径 精确到文件夹名 E:\fsl\nodeJs\coderwhy\day4\path
console.log(path.resolve(__dirname,'b/c/d')); //=>双重保险 E:\fsl\nodeJs\coderwhy\day4\path\b\c\d

path.join()与path.resolve()区别

path.join()

  • 将多个路径拼接在一起;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const path = require("path");
// 路径拼接 相对路径
{
const basePath = "/user/why";
const filename = "abc.txt";
console.log(path.join(basePath, filename)); // \user\why\abc.txt
}

{
const basePath = "/user/why";
const filename = "../abc.txt";
console.log(path.join(basePath, filename)); // \user\abc.txt (../返回上级目录user,所以路径上没有why)
}

path.resolve()

  • 将多个路径拼接在一起,最终一定会返回一个绝对路径
  • 给定的路径的序列是从右往左处理的,后面的每个path依次解析,一旦构造完一个完整的绝对路径,立即停止路径拼接;
  • 如果在处理完所有给定path的段之后,还没有生成绝对路径,则使用当前工作目录进行拼接,形成绝对路径;
  • path.resolve()什么都不传,就是当前路径;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const path = require("path");

// 路径拼接 绝对路径 (/会直接当成绝对路径)

// /会直接当成绝对路径,拼接完一个完整的绝对路径,剩下的不再拼接;
console.log(path.resolve("./abc/cba", "./why/hua", "/ccc.txt")); // E:\ccc.txt

// 每个路径相对路径是相对于的前面的拼接路径,若最终没有拼成绝对路径,会再次和__dirname进行拼接;
console.log(path.resolve("./abc/cba", "../why/hua", "./ccc.txt")); // E:\fsl\webpack\path模块\abc\why\hua\ccc.txt

// ps
console.log(__dirname); // E:\fsl\webpack\path模块

// path.resolve()什么都不传,就是当前路径;
console.log(path.resolve()); // E:\fsl\webpack\path模块

http模块

http模块用来做web服务器,传送门