Node.js(二)——fs、path、http模块
Node.js文件系统与HTTP模块核心功能摘要 Node.js通过fs模块提供文件操作能力,包括: 文件读写:readFile()读取文件内容,writeFile()写入内容 路径处理:使用__dirname解决动态路径拼接问题 path模块提供路径处理方法: join()拼接路径 basename()获取文件名 extname()获取扩展名 HTTP模块可创建Web服务器: createSer
一、fs文件系统模块
1.什么是文件系统模块
fs是Node.js官方提供的,用来操作文件的模块,它提供了一系列的方法和属性用来满足用户对文件的操作。
- fs.readFile() 读取指定文件的内容
- fs.writeFile() 向指定文件中写入内容
在js中如果需要fs来操作文件需要先引入:
const fs=require('fs')
‘fs’在我们安装node的时候就已经到电脑本地了
2.使用fs.readFile()来读取文件
fs.readFile(path[,options],callback)用[ ]括起来的就是可选参数,options默认值都是utf8
path路径,options以什么编码格式来读取文件(比如‘utf8’),callback通过回调函数拿到读取的结果
小🌰:
const fs=require('fs')
fs.readFile('./file/1.txt','utf8',function(error,data){
console.log(error,'error')
console.log('888')
console.log(data,'data')
})
文件结构如图:
终端输出:
读取结果:
读取成功的时候,error的值为null
读取失败的时候,dataStr的值为undefined
验证文件读取失败:看error返回的是否是null
3.使用fs.write()来写文件
fs.writeFile(path,data[,options],callback)
写入成功的话error是null,写入失败的话error是一个错误对象
fs.writeFile('./file/1.txt','你好呀','utf8',function(error){
console.log(error,'error')
})
这个回调函数没有data,error是null再去看文件里已经被写成功了
还可以使用这个来新建文件,运行下面这段之后可以看到file文件夹下面多了一个2.txt文件
const fs=require('fs')
fs.writeFile('./file/2.txt','哈哈哈2','utf8',function(error){
if(error===null){
return console.log('写入成功了')
}
console.log('写入失败了')
})
4.练习:将文件1的成绩写入到文件2中
先创建一个成绩文件1.txt,然后开写
const fs=require('fs')
fs.readFile('./file/1.txt','utf8',function(error,data){
if(error===null){
console.log('读到了数据:',data)
fs.writeFile('./file/2.txt',data,'utf8',function(error2){
if(error2===null){
console.log('写入成功了!!')
}
})
}
})

easy!!
5.fs路径动态拼接
在fs读写操作中,如果用./或者../这种很容易有拼接错误的问题
因为它不是先找到自己当前所在的路径然后再node xxx.js去运行的吗,实际上是用当前目录拼接上那个相对路径合成的,所以如果你在执行命令时所处的文件位置不对那就出错了
比如说我们之前的路径是 a/b/c/d下运行 node .\test.js,现在你改成a/b/c下运行 node d/test.js就会报错,因为它执行到那个文件看到的是./file/1.txt,那它就去找a/b/c下的./file/1.txt了
解决方法:
(1)用全路径
直接提供一个完整的路径,从盘符写到真正位置,直接在文件右键复制路径,以我复制的为例:
(mac)/Users/xxx/Desktop/my-backend-project/test.js
注意js中‘/’代表转移的意思,还需要补全,将‘/’写为‘//’就是一个真正的斜线了

这里mac跟windows不太一样,mac不写//也可以,写了也可以;但是node后面的路径直接用xx/yy就行,用.\xx\yy会报错
(2)__dirname
上面这种的话移植性非常差,如果将来路径改了之后前面那一大串都得重写。
那么node为我们提供了一个 成员__dirname,表示当前这个文件所处的目录
fs.readFile(__dirname+'/file/1.txt','utf8',function(error,data){
if(error===null){
console.log('读到了数据:',data)
}
})
二、path路径模块
1.什么是路径模块
path模块是node提供的用于处理路径的模块,用来满足用户对路径处理的需求。
- path.join(),用来将多个路径片段拼成一个完整的字符串
- path.basename(),从路径字符串中将文件名解析出来
- path.extname(),获取路径中的文件扩展名
引入方式:
const path=require('path')
2.path.join()方法
path.join([...paths]),参数个数没有要求 (我还以为是数组形式,结果是可选)
const path=require('path')
const str=path.join('/a','b/c','../','/e')
console.log(str,'str')

../会消除上一级路径,./没啥作用
然后还可以用__dirname,这样的话不用+了,用+可能会有问题,比如说__dirname+'./file/1.txt'就不对,但是用path.join(__dirname,'./file/1.txt')就没问题,会自己屏蔽掉.
path.join(__dirname,'file/1.txt')
输出:
/Users/xxx/Desktop/my-backend-project/file/1.txt str
3.path.basename()方法
path.basename(path[,ext]) ext是文件扩展名,这个方法会把路径的最后一部分内容返回回来
const path=require('path')
const str=path.basename('a/b/c/1.txt')
console.log(str,'str')

如果传入扩展名的话:const str=path.basename('a/b/c/1.txt','.html') 就会只得到文件名 1
4.path.extname()方法
path.extname(path)
const path=require('path')
const str=path.extname('a/b/c/1.txt')
console.log(str,'str')

三、时钟案例
将index-1.html里的(如下:)css、js和去除css和js的html(只引入,无代码)三个文件分别拆解出来
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>index首页</title>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
background-image: linear-gradient(to bottom right, red, gold);
}
.box {
width: 400px;
height: 250px;
background-color: rgba(255, 255, 255, 0.6);
border-radius: 6px;
position: absolute;
left: 50%;
top: 40%;
transform: translate(-50%, -50%);
box-shadow: 1px 1px 10px #fff;
text-shadow: 0px 1px 30px white;
display: flex;
justify-content: space-around;
align-items: center;
font-size: 70px;
user-select: none;
padding: 0 20px;
/* 盒子投影 */
-webkit-box-reflect: below 0px -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(0%, transparent), to(rgba(250, 250, 250, .2)));
}
</style>
</head>
<body>
<div class="box">
<div id="HH">00</div>
<div>:</div>
<div id="mm">00</div>
<div>:</div>
<div id="ss">00</div>
</div>
<script>
window.onload = function () {
// 定时器,每隔 1 秒执行 1 次
setInterval(() => {
var dt = new Date()
var HH = dt.getHours()
var mm = dt.getMinutes()
var ss = dt.getSeconds()
// 为页面上的元素赋值
document.querySelector('#HH').innerHTML = padZero(HH)
document.querySelector('#mm').innerHTML = padZero(mm)
document.querySelector('#ss').innerHTML = padZero(ss)
}, 1000)
}
// 补零函数
function padZero(n) {
return n > 9 ? n : '0' + n
}
</script>
</body>
</html>
直接上代码:(正则咱也不太会,每次遇见正则都是直接chat)
/<\/?style\b[^>]*>/gi
/是开始<
\/是为了不让/识别为转义,所以\/就是/
?表示的是前面的那个数量,也就是/ 0或1次,识别出来的是<style和</style
\b是单词边界,也就是style得是一个完整的单词 <styler 这种就不行
[^>]*匹配不是>的字符,多少都行
然后>
G是全局匹配,而不是找到第一个就停止
I表示不区分大小写
但是这个只能识别出<style></style>拿出那一堆还得截取字符串
/<style\b[^>]*>[\s\S]*?<\/style>/gi这个的话就是没有了\/,直接取出样式的那一堆代码
const fs=require('fs')
const path=require('path')
// console.log(path.join(__dirname,'/index-1.html'))
fs.readFile(path.join(__dirname,'/index-1.html'),'utf8',function(error,data){
if(error===null){
// 1. 提取所有 <style> 内容
const styleRegex = /<style\b[^>]*>[\s\S]*?<\/style>/gi;
const styleMatches = data.match(styleRegex);
const styleContent = styleMatches
? styleMatches.map(item => item.replace(/<\/?style\b[^>]*>/gi, '')).join('\n')
: '';
// 2. 提取所有 <script> 内容
const scriptRegex = /<script\b[^>]*>[\s\S]*?<\/script>/gi;
const scriptMatches = data.match(scriptRegex);
const scriptContent = scriptMatches
? scriptMatches.map(item => item.replace(/<\/?script\b[^>]*>/gi, '')).join('\n')
: '';
// 结果在这里!!!
console.log('===== 提取到的 CSS 样式 =====');
console.log(styleContent);
console.log('\n===== 提取到的 JS 脚本 =====');
console.log(scriptContent);
fs.writeFile(path.join(__dirname,'/index.css'),styleContent,function(error){
if(error===null){
console.log('css文件写入成功!')
}
})
fs.writeFile(path.join(__dirname,'/index.js'),scriptContent,function(error){
if(error===null){
console.log('js文件写入成功!')
}
})
let result = data.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '');
// 2. 删掉所有 <script>...</script>
result = result.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
// 3. 插入外部 CSS(放在 </head> 前面)
result = result.replace('</head>', ` <link rel="stylesheet" href="./index.css">\n</head>`);
// 4. 插入外部 JS(放在 </body> 前面)
result = result.replace('</body>', ` <script src="./index.js"></script>\n</body>`);
// 输出最终处理好的 HTML
console.log('===== 处理后的 HTML =====');
console.log(result);
fs.writeFile(path.join(__dirname,'/index.html'),result,function(error){
if(error===null){
console.log('html文件写入成功!')
}
})
}
})
// fs.readFile(__dirname)
注意点:
(1)fs.writeFile()只能创建文件,不能创建路径(不能自动创建文件夹)
(2)重复调用fs.writeFile()去写同一个文件,新写入的内容会覆盖之前的旧内容
四、http模块
1.什么是http模块
在网络节点中,负责消费资源的电脑,叫客户端;负责对外提供网络资源的电脑,叫服务器;http模块就是node提供用来创建web服务器的模块,通过http提供的http.createServer()就可以把一台普通的电脑,变成可以向外提供Web资源的服务器。
导入方式:
const http=require('http')
服务器与普通电脑的区别就是服务器上安装了web服务器软件,比如IIS、apache
比如当我们安装apache之后(电脑就有程序在监听你的127.0.0.1 80端口(默认)了),在根目录下放一个html文件,然后在浏览器输入127.0.0.1就可以看到这个页面,不过别人看不到这个网址
IP地址
是每个人电脑的唯一地址,IP地址具有唯一性
在自己电脑输入127.0.0.1,就能把自己电脑当作一台服务器进行访问了,127.0.0.1的域名对应的是localhost
域名就是代替IP地址的一个方便记忆的字符串型的地址方案(IP和域名是一一对应的关系,这个关系存放在域名服务器(DNS中))
端口号
计算机中的端口号类似于大楼的门牌号,比如我们平时运行多个项目,他们都运行在不同的端口号中,客户端发送过来的网络请求通过端口号交给对应的web服务。
注意:(1)一个端口号不能被多个web服务占用
(2)80端口在实际应用中可以被省略
2.创建最基本的web服务器
(1)导入http模块
const http = require('http')
(2)创建web服务器实例
http.createServer()
(3)为服务器实例绑定requst请求,监听客户端的请求
使用服务器实例的.on方法,绑定一个request事件处理函数
server.on('request',(req,res)=>{
console.log('77')
})
当有客户端请求这个服务就会触发这个回调函数,然后输出77
(4)启动服务器
调用服务器的.listen()方法就可以启动当前的web服务器实例
server.listen('80',()=>{
console.log('服务器启动成功')
})
然后依旧在终端去运行,运行完之后终端输出:(光标还在一直闪,在监听)
![]()
当我们在浏览器输入127.0.0.1:80,发现终端输出:

而且浏览器这时候会一直在转圈,这是因为我们没有给客户端任何响应

问题:listen为什么是启动用的,他不应该是监听吗?
listen监听=启动+等待请求(开启后只听不动),第一个参数写多少就只启动哪个端口,其他的端口不启动
server.listen('80'就好比在80房间号开门等你,浏览器进入127.0.0.1:80(127.0.0.1)就等于进了80房间,如果访问127.0.0.1:8080就会报错,因为8080没开门
监听=服务器开门=启动成功
request=收到请求之后做什么
3.req请求对象
服务端接收到客户端的请求之后就会调用server.on()为服务器绑定的request的事件处理函数
(node底部感知请求自动触发request事件)
req是回调函数中的请求对象,可以用来访问客户端的数据或属性
req.url是请求路径,req.method是请求方法(get/post、、、)
const http=require('http')
const server=http.createServer()
server.on('request',(req)=>{
console.log(req.url,'url')
console.log(req.method,'method')
})
server.listen('80',()=>{
console.log('启动')
})

浏览器默认只能发起get请求,如果想发起post请求的话可以用postman
4.res响应对象
在服务器的request
res.end向客户端发送指定内容,并且结束此次请求
之前我们客户端的请求服务端就只是监听没有发送任何结果,用end可以去发送
const http=require('http')
const server=http.createServer()
server.on('request',(req,res)=>{
res.end('哈哈哈')
})
server.listen('80',()=>{
console.log('启动')
})
然后启动之后我发现浏览器访问得到的是乱码

乱码解决:
(1)问了ai之后发现在发送之前加这么一句就好了(英文没问题):
res.setHeader('Content-Type','text/plain; charset=utf-8')
(2)或者是这样:
res.setHeader('Content-Type','text/html; charset=utf-8')
res.end('<h1>你好哈哈</h1>')

注意:箭头函数如果要加上res的话必须得写两个(req,res),req的话写他自己就行
顺序不能乱,node是按顺序传参
问题:为什么修改代码之后需要重启服务器
因为node的运行代码是一次性读取代码到内存之后就不再看文件了
硬盘的代码修改了但是内存里运行的还是老代码
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐



所有评论(0)