一、NodeJs全局对象global
全局对象是JS中的特殊对象,它与浏览器平台的window不完全相同,Nodejs中全局对象是global
.它的根本作用就是作为宿主
,全局对象可以看做全局变量的宿主,Nodejs全局对象上挂载许多属性.
NodeJs常见全局变量
- __filename: 返回正在
执行脚本文件的绝对路径
- __dirname: 返回正在
执行脚本所在目录
- timer类函数:
执行顺序
与事件循环
间的关系 - require:
实现模块的加载
- module、exports:
处理模块的导出
- process: 提供与当前进程互动的接口
- 内存情况: process.
memoryUsage()
- CPU情况: process.
cpuUsage()
- 运行目录: process.
cwd()
- node环境: process.
version
process.versions - cpu架构: process.
arch
- 用户环境: process.
env.NODE_ENV
process.env.PATH
- 获取用户工作目录: process.
env.USERPROFILE
process.env.HOME(mac下) - 系统平台: process.
platform
- 启动参数: process.
argv
process.execArgv - pid: process.
pid
process.ppid
- 运行时间: process.
uptime()
- 输入输出事件流:
// 设置字符编码 process.stdin.setEncoding('utf-8') // 设置一个是否可读的事件readable process.stdin.on('readable',()=>{ // 取出可读的东西 let chunk = process.stdin.read() if(chunk !== null){ // 写出来 process.stdout.write('data'+ chunk) } })
- 内存情况: process.
二、NodeJs核心模块
2.1 Path模块常用API
Path模块用于处理文件/目录的路径
- basename() 获取
路径中基础名称
// 01 返回的就是接收路径当中的最后一部分
console.log(path.basename(__filename)) // 01-path.js
// 02 第二个参数表示扩展名,如果说没有设置则返回完整的文件名称带后缀
console.log(path.basename(__filename, '.js')) // 01-path
// 03 第二个参数做为后缀时,如果没有在当前路径中被匹配到,那么就会忽略
console.log(path.basename(__filename, '.css')) //01-path.js
// 04 处理目录路径的时候如果说,结尾处有路径分割符,则也会被忽略掉
console.log(path.basename('/a/b/c')) // c
console.log(path.basename('/a/b/c/')) // c
- dirname() 获取
路径目录名
(路径)
// 返回路径中最后一个部分的上一层目录所在路径
console.log(path.dirname(__filename)) // /Users/.../02Path
console.log(path.dirname('/a/b/c')) // /a/b
console.log(path.dirname('/a/b/c/')) // /a/b
- extname() 获取路径中
扩展名称
// 返回路径中最后一个部分的上一层目录所在路径
console.log(path.extname(__filename)) // .js
console.log(path.extname('/a/b')) //
// 如果 path 路径当中存在多个点,它匹配的是最后一个点,到结尾的内容
console.log(path.extname('/a/b/index.html.js.css')) // .css
// 如果 path 路径当中存在多个点,它匹配的是最后一个点,到结尾的内容
console.log(path.extname('/a/b/index.html.js.')) // .
- isAbsolute()
判断
获取路径是否为绝对路径
console.log(path.isAbsolute("foo")); // false
console.log(path.isAbsolute("/foo")); // true
console.log(path.isAbsolute("///foo")); // true
console.log(path.isAbsolute("")); // false
console.log(path.isAbsolute(".")); // false
console.log(path.isAbsolute("../bar")); // false
- join()
拼接
多个路径片段
console.log(path.join('a/b', 'c', 'index.html')) // a/b/c/index.html
console.log(path.join('/a/b', 'c', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '../', 'index.html')) // /a/b/index.html
console.log(path.join('/a/b', 'c', './', 'index.html')) // /a/b/c/index.html
console.log(path.join('/a/b', 'c', '', 'index.html')) // /a/b/c/index.html
console.log(path.join('')) // .
- resolve()
返回绝对路径
console.log(path.resolve()) // /Users/***/path
console.log(path.resolve('/a', '/')) // /
console.log(path.resolve('/a', '/b')) // /b
console.log(path.resolve('/a', '../b')) // /b
console.log(path.resolve('a', 'b')) // /Users/***/a/b
console.log(path.resolve('index.html')) // /Users/***/path/index.html
- pasre()
解析路径
// { root: '/', dir: '/a/b/c', base: 'index.html', ext: 'html', name: 'index' }
console.log(path.parse('/a/b/c/index.html'))
// { root: '/', dir: '/a/b', base: 'c', ext: '', name: 'c' }
console.log(path.parse('/a/b/c/'))
// { root: '', dir: './a/b', base: 'c', ext: '', name: 'c' }
console.log(path.parse('./a/b/c/'))
- format()
序列化路径
const obj = path.parse('./a/b/c/')
console.log(path.format(obj)) // ./a/b/c
- normalize()
规范化路径
console.log(path.normalize('')) // .
console.log(path.normalize('a/b/c/d')) // a/b/c/d
console.log(path.normalize('a///b/c../d')) // a/b/c../d
console.log(path.normalize('a//\\/b/c\\/d')) // a/\/b/c\/d
console.log(path.normalize('a//\b/c\\/d')) // a/c\/d
2.2 全局变量之Buffer
Nodejs平台js可以实现IO,IO行为操作其实就是操作二进制数据,而buffer让js可以操作二进制.Buffer是Nodejs的内置类是一片内存空间
,目的是为了方便让cpu进行存取操作的时候可以有一个中间的存储区域
buffer是什么?在哪?做什么?
Buffer总结
- 无需require的一个全局变量
- 实现Nodejs平台下的
二进制数据操作
不占据
V8堆内存大小的内存空间
- 内存的使用由Node来控制,
由V8的GC回收
- 一般
配合Stream流
使用,充当数据缓冲区
创建Buffer
alloc
创建制定字节大小的buffer
// Buffer是一种内存空间的数据类型, 创建10个字节的buffer
const b1 = Buffer.alloc(10)
allocUnsafe
创建制定大小的buffer(不安全)
// 在内存中只要有空闲的空间(没有被垃圾回收的空间)就会拿过来使用,用的比较少
const b2 = Buffer.allocUnsafe(10)
console.log(b1)// <Buffer 00 00 00 00 00 00 00 00 00 00>
console.log(b2)// <Buffer 08 00 00 00 01 00 00 00 00 00>
from
接收数据,创建buffer
// 接收数据创建buffer 返回对应字符的16进制编码
const b3 = Buffer.from('中')
console.log(b3) // <Buffer e4 b8 ad>
const b4 = Buffer.from([0xe4, 0xb8, 0xad])
console.log(b4); // <Buffer e4 b8 ad>
console.log(b4.toString()); // 中
// 接收一个buffer生产的是一个新的buffer,内存空间是独立的
const b5= Buffer.alloc(3)
const b6 = Buffer.from(b5)
console.log(b5) // <Buffer 00 00 00>
console.log(b6) // <Buffer 00 00 00>
b5[0] = 1 // 修改
console.log(b5) // <Buffer 01 00 00>
console.log(b6) // <Buffer 00 00 00>
Buffer实例方法
let buf = Buffer.alloc(6);
- fill : 使用数据
填充
buffer
buf.fill(123,1)
buf.fill(123)
console.log(buf) // <Buffer 7b 7b 7b 7b 7b 7b>
console.log(buf.toString()) // {{{{{{
- write : 向buffer中
写入
数据
// 第二个参数是写入的位置 第三个参数是写入的长度
buf.write('123', 1, 4)
console.log(buf) // <Buffer 00 31 32 33 00 00>
console.log(buf.toString()) // 123
- toString : 从buffer中
提取
数据
buf = Buffer.from('韬光养晦')
console.log(buf) // <Buffer e9 9f ac e5 85 89 e5 85 bb e6 99 a6>
console.log(buf.toString('utf-8', 6, 12)) // 养晦
- slice :
截取
buffer
buf = Buffer.from("韬光养晦");
console.log(buf); // <Buffer e9 9f ac e5 85 89 e5 85 bb e6 99 a6>
let b1 = buf.slice(-3);
console.log(b1); // <Buffer e6 99 a6>
console.log(b1.toString()); // 晦
- indexOf : 在buffer中
查找
数据
// indexOf 查找是否存在并返回下标
buf = Buffer.from('爱前端')
console.log(buf) // <Buffer e7 88 b1 e5 89 8d e7 ab af>
console.log(buf.indexOf('前')) // 3
- copy :
拷贝
buffer中的数据
let b1 = Buffer.alloc(12)
let b2 = Buffer.from('学习')
// 将b2拷贝给b1 b1是容器 第一个3表示放置在b1的第三个位置 后面的3和6表示拷贝b2的第三个到第6个字节
b2.copy(b1,3,3,6)
console.log(b1.toString()) // 习
console.log(b2.toString()) // 学习
// 将b2拷贝给b1 第一个3表示放置在b1的第三个位置
b2.copy(b1,3)
console.log(b1.toString()) // 学
console.log(b2.toString()) // 学习
// 将b2拷贝给b1 第一个3表示放置在b1的第三个位置 第二个3表示拷贝b2的第三个到最后一个
b2.copy(b1,3,3)
console.log(b1.toString()) // 习
console.log(b2.toString()) // 学习
// 将b2全部拷贝给b1 从b1的开始位存起
b2.copy(b1)
console.log(b1.toString()) // 学习
console.log(b2.toString()) // 学习
Buffer静态方法
- concat : 将多个buffer
拼接
成一个新的buffer
let b1 = Buffer.from('拉勾')
let b2 = Buffer.from('教育')
let b = Buffer.concat([b1, b2])
console.log(b) // <Buffer e6 8b 89 e5 8b be e6 95 99 e8 82 b2>
console.log(b.toString()) // 拉勾教育
// 取前几位
let b2 = Buffer.concat([b1, b2],9)
console.log(b.toString()) // 拉勾教
- isBuffer :
判断
当前数据是否为buffer
// isBuffer
let b1 = '123'
console.log(Buffer.isBuffer(b1)) // false
自定义Buffer之split
ArrayBuffer.prototype.split = function (sep) {
let len = Buffer.from(sep).length
let ret = []
let start = 0
let offset = 0
while( offset = this.indexOf(sep, start) !== -1) {
ret.push(this.slice(start, offset))
start = offset + len
}
ret.push(this.slice(start))
return ret
}
let buf = 'zce吃馒头,吃面条,我吃所有吃'
let bufArr = buf.split('吃')
console.log(bufArr)
2.3 FS模块
FS是内置的核心模块,提供文件系统操作的API,在使用的过程中buffer(缓冲区)
和steram(数据流)
是绕不开的. fs分为基本操作类
和常用api
部分
先说一说文件
- 权限位
- 用户对于文件所具备的
操作权限
.分别是R
(读权限,对应八进制是4)、W
(写权限,对应八进制是2)、S
(执行权限,对应八进制是1) ,不具备操作权限是0. 操作系统将用户又分为3类,当前所有者(自己)、文件所属组(家人)、其他用户(其他人)
- 用户对于文件所具备的
- flag标识符
- r: 表示
可读
- r+: 不清空,直接写.写在前
- w: 表示
可写
- w+: 清空再写
- s: 表示
同步
操作 - +: 表示执行
相反
操作 - x: 表示
排他
的操作方式 - a: 表示
追加
操作
- r: 表示
- 文件描述符
- 操作系统中文件描述符一般从3开始,0(标准输入)、1(标准输出)、2 (标准错误)已经被占用了.
- 在后期执行fs.open打开某一个文件的时候会得到一个fd, fd就是从3开始的.
- 而fd就是操作系统分配给被打开文件的描述符
文件操作API
- readFile: 从指定文件中
读取
数据- 如果路径不存在会报错
// 在node中遵循错误优先
fs.readFile(path.resolve("data.txt"), "utf-8", (err, data) => {
console.log(err);
if (!null) {
console.log(data);
}
});
- writeFile: 向指定文件中
写入
数据- 如果路径不存在就会去创建文件
fs.writeFile('data.txt', '123', {
mode: 438,// 操作权限:在windows八进制中对应0o666,对应的十进制是438,也就是可读可写不可执行
flag: 'w+',// w+: 写入方式,清空再写入 r+:不清空,在第一个位置写入
encoding: 'utf-8'// 字符编码
}, (err) => {
if (!err) {
fs.readFile('data.txt', 'utf-8', (err, data) => {
console.log(data)
})
}
})
- appendFile:
追加
的方式向文件中写入数据
fs.appendFile('data.txt', 'hello node.js',{}, (err) => {
console.log('写入成功')
})
- copyFile: 将某个文件中的数据
拷贝
到另一文件
fs.copyFile('data.txt', 'test.txt', () => {
console.log('拷贝成功')
})
- watchFile: 对指定文件进行
监控
fs.watchFile("data.txt", { interval: 20 }, (curr, prev) => {
// interval: 每20s监控一下,文件是否发生变化.发生变化了执行回调函数
// mtime: 修改时间
// curr: 修改之后的信息 prev:修改之前的信息
if (curr.mtime !== prev.mtime) {
console.log("文件被修改了");
fs.unwatchFile("data.txt");
}
});
文件操作实现md转html
const fs = require('fs')
const path = require('path')
const { marked } = require('marked'); // npm init npm i marked
const browserSync = require('browser-sync') // npm i browser-sync
/**
* 01 读取 md 和 css 内容
* 02 将上述读取出来的内容替换占位符,生成一个最终需要展的 Html 字符串
* 03 将上述的 Html 字符写入到指定的 Html 文件中
* 04 监听 md 文档内容的变经,然后更新 html 内容
* 05 使用 browser-sync 来实时显示 Html 内容
*/
let mdPath = path.join(__dirname, 'index.md')
console.log(mdPath);
let cssPath = path.resolve('github.css')
let htmlPath = mdPath.replace(path.extname(mdPath), '.html')
const read = () => {
fs.readFile(mdPath, 'utf-8', (err, data) => {
// 将 md--》html
let htmlStr = marked(data)
console.log(htmlStr);
fs.readFile(cssPath, 'utf-8', (err, data) => {
let retHtml = temp.replace('{{content}}', htmlStr).replace('{{style}}', data)
// 将上述的内容写入到指定的 html 文件中,用于在浏览器里进行展示
fs.writeFile(htmlPath, retHtml, (err) => {
console.log('html 生成成功了')
})
})
})
}
fs.watchFile(mdPath, (curr, prev) => {
if (curr.mtime !== prev.mtime) {
read()
}
})
read()
browserSync.init({
browser: '',
server: __dirname,
watch: true,
index: path.basename(htmlPath)
})
const temp = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.markdown-body {
box-sizing: border-box;
min-width: 200px;
max-width: 1000px;
margin: 0 auto;
padding: 45px;
}
@media (max-width: 750px) {
.markdown-body {
padding: 15px;
}
}
{{style}}
</style>
</head>
<body>
<div class="markdown-body">
{{content}}
</div>
</body>
</html>
文件打开与关闭
fs.open
打开某一个文件的时候会得到一个fd, fd就是从3开始的.
而fd就是操作系统分配给被打开文件的描述符
const fs = require('fs')
const path = require('path')
// open
fs.open(path.resolve('data.txt'), 'r', (err, fd) => {
console.log(fd)
})
// close
fs.open('data.txt', 'r', (err, fd) => {
console.log(fd)
fs.close(fd, err => {
console.log('关闭成功')
})
})
大文件读写操作
const fs = require('fs')
// read : 所谓的读操作就是将数据从磁盘文件中写入到 buffer 中
let buf = Buffer.alloc(10)
/**
* fd 定位当前被打开的文件
* buf 用于表示当前缓冲区
* offset 表示当前从 buf 的哪个位置开始执行写入
* length 表示当前次写入的长度
* position 表示当前从文件的哪个位置开始读取
*/
fs.open('data.txt', 'r', (err, rfd) => {
console.log(rfd)
fs.read(rfd, buf, 1, 4, 3, (err, readBytes, data) => {
console.log(readBytes)
console.log(data)
console.log(data.toString())
})
})
// write 将缓冲区里的内容写入到磁盘文件中
buf = Buffer.from('1234567890·')
fs.open('b.txt', 'w', (err, wfd) => {
fs.write(wfd, buf, 2, 4, 0, (err, written, buffer) => {
console.log(written, '----')
fs.close(wfd)
})
})
文件拷贝自定义实现
const fs = require('fs')
/**
* 01 打开 a 文件,利用 read 将数据保存到 buffer 暂存起来
* 02 打开 b 文件,利用 write 将 buffer 中数据写入到 b 文件中
*/
let buf = Buffer.alloc(10)
// 01 打开指定的文件
// fs.open('a.txt', 'r', (err, rfd) => {
// // 03 打开 b 文件,用于执行数据写入操作
// fs.open('b.txt', 'w', (err, wfd) => {
// // 02 从打开的文件中读取数据
// fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
// // 04 将 buffer 中的数据写入到 b.txt 当中
// fs.write(wfd, buf, 0, 10, 0, (err, written) => {
// console.log('写入成功')
// })
// })
// })
// })
// 02 数据的完全拷贝
// fs.open('a.txt', 'r', (err, rfd) => {
// fs.open('b.txt', 'a+', (err, wfd) => {
// fs.read(rfd, buf, 0, 10, 0, (err, readBytes) => {
// fs.write(wfd, buf, 0, 10, 0, (err, written) => {
// fs.read(rfd, buf, 0, 5, 10, (err, readBytes) => {
// fs.write(wfd, buf, 0, 5, 10, (err, written) => {
// console.log('写入成功')
// })
// })
// })
// })
// })
// })
const BUFFER_SIZE = buf.length
let readOffset = 0
fs.open('a.txt', 'r', (err, rfd) => {
fs.open('b.txt', 'w', (err, wfd) => {
function next () {
fs.read(rfd, buf, 0, BUFFER_SIZE, readOffset, (err, readBytes) => {
console.log(readBytes);
if (!readBytes) {
// 如果条件成立,说明内容已经读取完毕
fs.close(rfd, ()=> {})
fs.close(wfd, ()=> {})
console.log('拷贝完成')
return
}
readOffset += readBytes
fs.write(wfd, buf, 0, readBytes, (err, written) => {
next()
})
})
}
next()
})
})
FS之目录操作API
- access: 判断文件或者目录
是否具有操作权限
,或者判断当前文件是否存在
fs.access('a.txt', (err) => {
if (err) {
console.log(err)
} else {
console.log('有操作权限')
}
})
- stat: 获取
目录及文件信息
fs.stat('a.txt', (err, statObj) => {
console.log(statObj)
console.log(statObj.size)
console.log(statObj.isFile())
console.log(statObj.isDirectory())
})
- mkdir:
创建目录
fs.mkdir('a/b/c', {recursive: true}, (err) => {
if (!err) {
console.log('创建成功')
}else{
console.log(err)
}
})
- rmdir:
删除目录
fs.rmdir('a/b', {recursive: true}, (err) => {
if (!err) {
console.log('删除成功')
} else {
console.log(err)
}
})
- readdir:
读取目录中的内容
fs.readdir('a/b/c', (err, files) => {
console.log(files)
})
- unlink:
删除指定文件
fs.unlink('a/b/c/index.html', (err) => {
if (!err) {
console.log('删除成功')
}
})
创建目录之同步实现(mkdirSync)
const fs = require('fs')
const path = require('path')
/**
* 01 将来调用时需要接收类似于 a/b/c ,这样的路径,它们之间是采用 / 去行连接
* 02 利用 / 分割符将路径进行拆分,将每一项放入一个数组中进行管理 ['a', 'b', 'c']
* 03 对上述的数组进行遍历,我们需要拿到每一项,然后与前一项进行拼接 /
* 04 判断一个当前对拼接之后的路径是否具有可操作的权限,如果有则证明存在,否则的话就需要执行创建
*/
function makeDirSync(dirPath) {
console.log(dirPath);
let items = dirPath.split(path.sep)
console.log(items);
for (let i = 1; i <= items.length; i++) {
let dir = items.slice(0, i).join(path.sep)
try {
fs.accessSync(dir)
} catch (err) {
fs.mkdirSync(dir)
}
}
}
const str = path.join(__dirname, 'a\\b\\c')
console.log(str);
makeDirSync(str)
创建目录之异步实现(mkdir)
const fs = require('fs')
const path = require('path')
const {promisify} = require('util')
// function mkDir (dirPath, cb) {
// let parts = dirPath.split('/')
// let index = 1
// function next () {
// if (index > parts.length) return cb && cb()
// let current = parts.slice(0, index++).join('/')
// fs.access(current, (err) => {
// if (err) {
// fs.mkdir(current, next)
// }else{
// next()
// }
// })
// }
// next()
// }
// mkDir('a/b/c/d', () => {
// console.log('创建成功')
// })
// 将 access 与 mkdir 处理成 async... 风格
const access = promisify(fs.access)
const mkdir = promisify(fs.mkdir)
async function myMkdir (dirPath, cb) {
let parts = dirPath.split('/')
for(let index = 1; index <= parts.length; index++) {
let current = parts.slice(0, index).join('/')
try {
await access(current)
} catch (err) {
await mkdir(current)
}
}
cb && cb()
}
myMkdir('a/b/c/e', () => {
console.log('创建成功')
})
递归删除或文件
const { dir } = require('console')
const fs = require('fs')
const path = require('path')
function myRmdir(dirPath, cb) {
// 判断当前 dirPath 的类型
fs.stat(dirPath, (err, statObj) => {
console.log(dirPath);
if (!err) {
if (statObj.isDirectory()) {
fs.rmdir(dirPath,cb)
} else {
// 文件---> 直接删除
fs.unlink(dirPath, cb)
}
}
})
}
myRmdir(path.join(__dirname, 'a/b/c/e/d/txt.txt'), (err) => {
console.log('删除成功了')
})