了解Node.js与内置模块
什么是Node.js?
Node.js® is an open-source, cross-platform JavaScript runtime environment.
node.js是一个开源跨平台的js运行环境。
前端的运行环境就是浏览器。
注意:Node.js中无法调用DOM和BOM等浏览器内置API。
Node.js中的顶级对象为global,也可以用globalThis访问顶级对象.
如下代码会报错
// BOM
console.log(window);
console.log(history)
console.log(navigator)
console.log(location)
// DOM
console.log(document)
//AJAX
let xhr = new XMLHttpRequest();
浏览器中的JavaScript的组成部分
js核心语法:变量、数据类型;循环、分支、判断;函数、作用域、this等等
WebAPI:DOM操作、BOM操作,基于XMLHttpRequest的Ajax操作
为什么js可以在浏览器中执行
不同的浏览器有不同的JavaScript解析引擎:
Chrome浏览器的V8解析引擎性能最好。
为什么js可以操作DOM和BOM
每个浏览器都内置了DOM和BOM的API函数,因此浏览器中的js才可以调用他们。
浏览器中的JavaScript运行环境
运行环境是指代码正常运行所需要的必要环境。
V8引擎负责解析和执行JavaScript代码
内置API是由运行环境提供的特殊接口,只能在所属的运行环境中被调用。
JavaScript能否做后端开发
JavaScript借助node.js可以进行后台开发,单独不行。node.js可以作为后端运行环境和JavaScript完成后端开发。
node的安装和使用
node的安装
node官网可以下载两个版本,LTS是长期支持稳定版本,适用于企业大型项目。
current是最新的,可以尝试新特性但是可能存在漏洞和安全性问题。
终端输入node -v可以查看安装的版本
node的使用
- 打开终端win+r输入cmd进入终端
- 输入js文件的路径,cd可以切换路径 d:可以切换c盘d盘
- 运行命令:node demo.js
如何打开当前路径下的终端,可以在当前路径的地址栏输入cmd回车或者在空白处按住shift不松手鼠标右键打开powershell。
终端快捷键
↑ 快速定位到上次执行的命令
tab 快速补全路径
esc 快速清空当前输入的命令
cls 清空终端
文件写入
fs模块可以实现与硬盘的交互,例如文件的创建、删除、重命名、移动,还有文件内容的写入、读取,以及文件夹的相关操作。
若在js代码中使用fs模块操作文件,需要先导入
const fs=require(‘fs’)
writeFile异步写入
向指定文件中写入内容fs.writeFile(file, data[, options], callback)
file:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径
data:必选参数,表示要写入的内容
options:可选参数,表示以什么编码格式来写入文件内容,默认值是utf8。
callback:必选参数,文件写入完成后的回调函数。
const fs = require('fs')
fs.writeFile('./files/2.txt', 'hellonodejs', function (err) {
console.log('写入成功!' + err)
// 文件写入成功,err的值等于null
// 文件写入失败,err的值等于一个错误对象
})
运行结果截图
判断文件是否写入成功
const fs = require('fs')
fs.writeFile('./files/2.txt', 'hellonodejs', function (err) {
if (err) {
return console.log('文件写入失败!'+err.message)
}
console.log('写入成功!' )
})
运行截图
writeFileSync同步写入
fs.writeFileSync('./data.txt','test');
性能不高的场景可以使用同步写入。
appendFile/appendFileSync追加写入
fs.appendFile('./files/2.txt', '这是中文附加的字', err => {
if (err) {
console.log('写入失败');
return;
}
console.log('追加写入成功')
});
fs.appendFileSync('./files/2.txt', '\r\n这是中文附加的字')
createWriteStream流式写入
语法: fs.createWriteStream(path[,options])
参数说明:
path文件路径
options选项配置(可选)
返回值:Object
代码示例:
// 1.导入fs模块
const fs = require('fs');
// 2.创建写入流对象
const ws = fs.createWriteStream('./files/给翠花的信.txt');
// 3.write
ws.write('亲爱滴翠花\r\n');
ws.write('我喜欢你很久了\r\n');
ws.write('可以借五毛钱嘛\r\n');
// 4.关闭通道
ws.close();
程序打开一个文件是需要消耗资源的,流式写入可以减少打开关闭文件的次数。
流式写入适用于大文件写入或者频繁写入的场景,writeFile适合与写入频率较低的场景。
写入文件的场景
当需要持久化保存数据的时候,应该想到文件写入
下载文件
安装软件
保存程序日志,如git
编辑器保存文件
视频录制
文件读取
readFile异步读取
fs.readFile(path[, options], callback)
path:必选参数,字符串,表示文件的路径。
options:可选参数,表示以什么编码格式来读取文件。
callback:必选参数,文件读取完成后,通过回调函数拿到读取的结果。
const fs = require('fs')
fs.readFile('./files/demo.txt', 'utf8', function (err, dataStr) {
console.log(err)
console.log('------')
console.log(dataStr)
})
callback回调函数,拿到读取的失败和成功的结果,err,dataStr
通过本路径下的powershell运行node
node 1
脚本文件名称过长使用tab键自动补全。
运行截图
读取成功err的值是null
读取失败err的值是错误对象,dataStr的值是undefined
判断文件是否读取成功
可以判断err对象是否是null,从而知晓文件读取的结果
const fs = require('fs')
fs.readFile('./files/demo.txt', 'utf8', function (err, result) {
if (err) {
return console.log('文件读取失败!' + err.message)
}
console.log('文件读取成功!' + result)
})
运行结果截图
readFileSync同步读取
const fs = require('fs');
fs.readFile('./files/给翠花的信.txt', (err, data) => {
if (err) {
console.log('读取失败');
return;
}
console.log(data.toString());
});
运行结果截图
createReadStream流式读取
const fs = require('fs');
const rs = fs.createReadStream('./files/匆匆那年.mp3');
rs.on('data', chunk => {
console.log(chunk.length);
console.log(chunk.toString());
})
流式读取chunk.length=65536字节对应的是64kb,就是流式读取每次在存储中读取64kb的内容。如果打印chunk.toString()会出现乱码,因为mp3音频不能打印成字符。
// end可选事件
rs.on('end',()=> {
console.log('读取完成');
});
读取文件应用场景
- 电脑开机
- 程序运行
- 编辑器打开文件
- 查看图片
- 播放视频
- 播放音乐
- git查看日志
- 上传文件
- 查看聊天记录
文件复制
第一种方式可以采用readFile读取文件内容,具体步骤先使用readFileSync读取文件,再用writeFileSync写入文件副本,即可完成。
const fs = require(('fs'));
let data = fs.readFileSync('./files/匆匆那年.mp3');
fs.writeFileSync('./files/匆匆那年-1.mp3', data);
第二种方法就是流式操作,创建读取流对象然后创建写入流对象,绑定data事件。
const fs = require(('fs'));
const rs = fs.createReadStream('./files/匆匆那年.mp3');
const ws = fs.createWriteStream('./files/匆匆那年-2.mp3');
rs.on('data', chunk => {
ws.write(chunk);
});
运行结果截图
第二种方式占用资源更少一些,所以第二种方式更好一些。流式读取是块读取,内容一块一块被读取,占用的内存较少。
可以通过引入process模块,调用memoryUsage()方法查看内存占用情况。rss:表示node进程占用的内存总量。
const fs = require(('fs'));
const process = require('process');
let data = fs.readFileSync('./files/匆匆那年.mp3');
fs.writeFileSync('./files/匆匆那年-1.mp3', data);
console.log(process.memoryUsage());//rss
const rs = fs.createReadStream('./files/匆匆那年.mp3');
const ws = fs.createWriteStream('./files/匆匆那年-2.mp3');
//绑定data事件
rs.on('data', chunk => {
ws.write(chunk);
});
rs.on('end', () => {
console.log(process.memoryUsage());//24383488
})
在如图所示的rss值当中,流式操作的值更大因为文件太小。文件比较大的时候才会明显显示出流式操作更节约内存.
或者可以不绑定data事件,使用管道命令快速实现复制
rs.pipe(ws)
文件移动与重命名
在node.js中我们可以使用rename或者renameSync来移动和重命名文件或者文件夹
语法
fs.rename(oldPath,newPath,callback)
fs.renameSync(oldPath,newPath)
参数说明:
oldPath文件当前路径
newPath文件新的路径
callback操作后的回调
代码示例
const fs = require('fs')
fs.rename('./6文件赋值.js', './files/6文件复制.js', (err) => {
if (err) throw err;
console.log('移动完成')
});
fs.renameSync('./6文件赋值.js', './files/6文件复制.js');
文件删除
Node.js中使用unlink或者unlinkSync来删除文件
语法
fs.unlink(path,callback)
fs.unlinkSync(path)
参数说明:
path文件路径
callback操作后的回调
代码示例
const fs = require('fs')
fs.unlink('./test.txt', err => {
if (err) throw err;
console.log('删除成功');
});
fs.unlinkSync('./test2.txt');
// 调用rm方法 rmRync
fs.rm('./论语.txt', err => {
if (err) {
console.log('delete successfully');
return;
}
console.log('删除成功');
})
文件夹操作
借助Node.js的能力,我们可以对文件夹进行创建、读取、删除等操作
mkdir/mkdirSync 创建文件夹
readdir/readdirSync 读取文件夹
rmdir/rmdirSync 删除文件夹
mkdir创建文件夹
fs.mkdir(path[,options],callback)
fs.mkdirSync(path[,options])
options选项配置(可选)
下面的代码可以创建一个名称为html的文件夹
const fs = require('fs');
fs.mkdir('./html', err => {
if (err) {
console.log('创建失败');
return;
}
console.log('创建成功');
});
下面看一下递归创建文件夹的代码
fs.mkdir('./a/b/c', { recursive: true }, err => {
if (err) {
console.log('创建失败');
return;
}
console.log('创建成功');
});
注意递归创建需要{ recursive: true },才可以成功的创建。
readdir读取文件夹
那么如何读取文件夹呢
fs.readdir('./files', (err, data) => {
if (err) {
return console.log('读取失败');
}
console.log(data);
});
rmdir删除文件夹
rm;remove移除
下面的代码用来演示删除html文件夹
const fs = require('fs');
fs.rmdir('./html', err => {
if (err) {
return console.log('删除失败')
}
console.log('删除成功');
});
// 递归删除
fs.rmdir('./a', { recursive: true }, err => {
if (err) {
return console.log('删除失败');
}
console.log('删除成功');
});
查看资源状态
stat或者statSync查看资源的详细信息
代码示例
const fs = require('fs');
fs.stat('./files/匆匆那年.mp3', (err, data) => {
if (err) {
return console.log('操作失败')
}
console.log(data);
console.log(data.isFile());
console.log(data.isDirectory());
});
结果值对象结构:size文件体积,birthday创建时间,mtime最后修改时间
isFile检测是否为文件,isDirectory检测是否是文件夹
相对路径和绝对路径
const fs = require('fs');
// 相对路径
fs.writeFileSync('./index.html', 'love');
fs.writeFileSync('index.html', 'love');
fs.writeFileSync('../index.html', 'love');
// 绝对路径
fs.writeFileSync('D:/index.html', 'love');
fs.writeFileSync('/index.html', 'love');
相对路径参照物:命令行的参照物
相对路径问题
在使用fs模块操作文件时。如果提供的操作路径是以./或者…/开头的相对路径时,很容易出现路径动态拼接错误的问题。
原因:代码在运行的时候,会以执行node命令所处的目录,动态拼接出被操作文件的完整路径。
fs.readFile('./files/1.txt','utf8',function(err.,dataStr){
if(err){
return console.log('读取文件失败!'+err.message)
}
console.log('读取文件成功!'+dataStr)
})
如果出现了路径拼接错误的问题,是因为提供了./或者…/开头的相对路径
如果要解决这个问题,可以直接提供一个完整的文件存放路径就行
fs.readFile('D:\\VUE\\nodejs\\files\\1.txt','utf8',function(err,dataStr){
if(err){
return console.log('读取文件失败!'+err.message)
}
console.log('读取文件成功!'+dataStr)
})
_dirname
// __dirname表示当前文件所处目录的绝对路径
console.log(__dirname)
__dirname所代表的值不会随着执行命令node路径动态拼接而变化,是个恒定的值
最佳实践
fs.readFile(__dirname+'./files/1.txt','utf8',function(err,dataStr){
if(err){
return console.log('读取文件失败!'+err.message)
}
console.log('读取文件成功!'+dataStr)
})
练习-考试成绩整理
使用fs文件系统模块,将素材目录下成绩.txt文件中的考试数据,整理到成绩-ok.txt文件中
核心实现步骤
- 导入需要的fs文件系统模块
- 使用fs.readFile()方法,读取素材目录下的成绩.txt文件
- 判断文件是否读取失败
- 文件读取成功后,处理成绩数据
- 将处理完成的成绩数据,调用fs.writeFile()方法,写入新文件成绩-ok.txt中
// 1.导入fs模块
const fs = require('fs')
// 2.调用fs.readFile()读取文件内容
fs.readFile('./素材/成绩.txt', 'utf8', function (err, dataStr) {
// 3.判断是否读取成功
if (err) {
return console.log('读取文件失败!'+err.message)
}
// console.log('读取文件成功'+dataStr)
// 4.1先把成绩的数据,按照空格进行分割
const arrOld = dataStr.split(' ')
// 4.2循环分割后的数组,对每一项数据进行字符串的替换操作
const arrNew = []
arrOld.forEach(items => {
arrNew.push(items.replace('=',':'))
})
// 4.3把新数组中的每一项,进行合并,得到一个新的字符串
const newStr = arrNew.join('\r\n')
console.log(newStr)
fs.writeFile('./files/成绩-ok.txt', newStr, function (err) {
if (err) {
return console.log('成绩写入失败'+err.message)
}
console.log('成绩写入成功')
})
})
练习
批量重命名
首先,输出files文件夹的所有文件信息
const fs = require('fs');
// 读取code文件夹
const files = fs.readdirSync('./files');
// 遍历数组
files.forEach(item => {
console.log(item);
})
终端输出:
PS D:\VUE\nodejs> node .\14批量重命名.js
1.txt
2.txt
3.txt
6文件复制.js
demo.txt
匆匆那年-1.mp3
匆匆那年-2.mp3
匆匆那年.mp3
成绩-ok.txt
给翠花的信.txt
完整的代码
const fs = require('fs');
// 读取code文件夹
const files = fs.readdirSync('./files');
// 遍历数组
files.forEach(item => {
// 拆分文件名
let data = item.split('-');
let [num, name] = data;
// 判断
if (Number(num) < 30) {
num = '0' + num;
}
// 创建新的文件名
let newName = num + '-' + name;
// console.log(newName);
// 重命名
fs.renameSync(`./files/${item}`, `./files/${newName}`);
})
总结注意点
fs提供了同步、回调和基于promise的三种形式。同步api会阻塞线程,但对于某些场景,使用同步方法会更方便、更易理解
尽量使用promise方式,回调容易造成嵌套地狱
对于大文件,使用文件流的方式来读写文件 createReadStream 和 createWriteStream 来减少内存占用
三方npm包 fs-extra 是fs的一个拓展,提供了很多更方便的api
.forEach(item => {
// 拆分文件名
let data = item.split('-');
let [num, name] = data;
// 判断
if (Number(num) < 30) {
num = '0' + num;
}
// 创建新的文件名
let newName = num + '-' + name;
// console.log(newName);
// 重命名
fs.renameSync(`./files/${item}`, `./files/${newName}`);
})
总结注意点
fs提供了同步、回调和基于promise的三种形式。同步api会阻塞线程,但对于某些场景,使用同步方法会更方便、更易理解
尽量使用promise方式,回调容易造成嵌套地狱
对于大文件,使用文件流的方式来读写文件 createReadStream 和 createWriteStream 来减少内存占用
三方npm包 fs-extra 是fs的一个拓展,提供了很多更方便的api