常见模块
一、内置模块 fs
fs 是File System的缩写,表示文件系统。
对于任何一个为服务器端服务的语言或者框架通常都会有自己的文件系统:
- 因为服务器需要将各种数据、文件等放置到不同的地方;
- 比如用户数据可能大多数是放到数据库中的
- 比如某些配置文件或者用户资源(图片、音视频)都是以文件的形式存在于操作系统上的;
Node 也有自己的文件系统操作模块,就是 fs:
- 借助于 Node 封装的文件系统,可以在任何的操作系统(window、Mac Os、Linux)上面直接去操作文件;
- 这也是 Node 可以开发服务器的一大原因,也是它可以成为前端自动化脚本等热门工具的原因;
Node 文件系统的 API: https://nodejs.org/docs/latest-v16.x/api/fs.html
这些API大多数都提供三种操作方式:
- 方式一:同步操作文件,代码会被阻塞,不会继续执行;
- 方式二:异步回调函数操作文件,代码不会被阻塞,需要传入回调函数,当获取到结果时,回调函数被执行;
- 方式三:异步 Promise 操作文件,代码不会被阻塞,通过 fs.promises 调用方法操作,会返回一个 Promise,可以通过 then、catch 进行处理;
1、fs 文件读取的 api
fs.readFile(path[, options], callback):读取文件的内容
- 如果不填写 encoding,返回的结果是 Buffer
aaa.txt
txt
hello world!
你好,橘米,方式一:同步操作文件
javascript
const fs = require('fs')
const res1 = fs.readFileSync('./abc.txt')
console.log(res1.toString())
console.log('res1后续代码')
const res2 = fs.readFileSync('./abc.txt', {
encoding: 'utf-8',
})
console.log(res2)
console.log('res2后续代码')
方式二:异步回调函数操作文件
javascript
fs.readFile(
'./abc.txt',
{
encoding: 'utf-8',
},
(err, data) => {
if (err) {
console.log('读取文件错误', err)
return
}
console.log('读取文件结果', data)
}
)
console.log('异步回调函数后续代码')
方式三:异步 Promise 操作文件
javascript
fs.promises
.readFile('./abc.txt', { encoding: 'utf-8' })
.then(res => {
console.log('读取文件结果', res)
})
.catch(err => {
console.log('读取文件错误', err)
})
console.log('异步读取:promise后续代码')
2、fs 文件描述符的使用
文件描述符(File descriptors)是什么呢?
- 在常见的操作系统上,对于每个进程,内核都维护着一张当前打开着的文件和资源的表格
- 每个打开的文件都分配了一个称为文件描述符的简单的数字标识符
- 在系统层,所有文件系统操作都使用这些文件描述符来标识和跟踪每个特定的文件
- Windows 系统使用了一个虽然不同但概念上类似的机制来跟踪资源
为简化用户的工作,Node.js 抽象出操作系统之间的特定差异,并为所有打开的文件分配一个数字型的文件描述符
fs.open()方法用于分配新的文件描述符
- 一旦被分配,则文件描述符可用于从文件读取数据向文件写入数据、或请求关于文件的信息
bbb.txt
txt
bbbjavascript
const fs = require('fs')
// 打开一个文件
fs.open('./bbb.txt', (err, fd) => {
if (err) {
console.log('打开文件错误', err)
return
}
// 1、获取文件描述符
console.log('fd=>', fd)
// 2、读取文件信息
fs.fstat(fd, (err, stats) => {
if (err) return
console.log(stats)
// 3、手动关闭文件
fs.close(fd)
})
})
3、fs 文件写入的 api
fs.writeFile(file, data[, options],callback):在文件中写入内容
flag 选项:
w打开文件写入,默认值;w+打开文件进行读写(可读可写),如果不存在则创建文件,r打开文件读取,读取时的默认值;r+打开文件进行读写,如果不存在那么抛出异常,a打开要写入的文件,将流放在文件末尾。如果不存在则创建文件;a+打开文件以进行读写(可读可写),将流放在文件未尾。如果不存在则创建文件
javascript
const fs = require('fs')
// 1、有一段内容
const content = 'hello world, my name is gmi!'
// 2、文件的写入操作
fs.writeFile('./ccc.txt', content, { encoding: 'utf-8', flag: 'a' }, err => {
if (err) {
console.log('文件写入错误', err)
return
}
console.log('文件写入成功')
})ccc.txt
txt
hello world, my name is gmi!4、fs 文件夹操作
创建
javascript
const fs = require('fs')
// 创建文件夹 directory
fs.mkdir('./gmi', err => {
console.log(err)
})读取
javascript
const fs = require('fs')
// 读取文件夹
// 1、读取文件夹,获取到文件夹中文件的字符串
fs.readdir('./gmi', (err, files) => {
console.log(files)
})
// 2、读取文件夹,获取文件夹中文件的信息
fs.readdir('./gmi', { withFileTypes: true }, (err, files) => {
files.forEach(item => {
if (item.isDirectory()) {
console.log('item是一个文件夹', item.name)
fs.readdir(
`./gmi/${item.name}`,
{ withFileTypes: true },
(err, files) => {
console.log(files)
}
)
} else {
console.log('item是一个文件', item.name)
}
})
})
// 3、递归读取文件夹中的所有文件
function readDirectory(path) {
fs.readdir(path, { withFileTypes: true }, (err, files) => {
files.forEach(item => {
if (item.isDirectory()) {
readDirectory(`${path}/${item.name}`)
} else {
console.log('读取到的文件', item.name)
}
})
})
}
readDirectory('./gmi')重命名
javascript
const fs = require('fs')
// 1、对文件夹重命名
fs.rename('./hn', './Gg', err => {
console.log('重命名结果', err)
})
// 2、对文件重命名
fs.rename('./ddd.txt', './eee.txt', err => {
console.log('重命名结果', err)
})二、内置模块 events
Node 中的核心 API 都是基于异步事件驱动的:
- 在这个体系中,某些对象(发射器(Emitters))发出某一个事件;
- 我们可以监听这个事件(监听器 Listeners),并且传入的回调函数,这个回调函数会在监听到事件时调用
发出事件和监听事件都是通过 EventEmitter 类来完成的,它们都属于 events 对象。
- emitter.on(eventName, listener):监听事件,也可以使用 addListener;
- emitter.off(eventName, listener):移除事件监听,也可以使用 removeListener;
- emitter.emit(eventName[, ...args]):发出事件,可以携带一些参数;
基本使用
javascript
const EventEmitter = require('events')
// 创建EventEmitter实例
const emitter = new EventEmitter()
// 监听事件
emitter.on('gmi', () => {
console.log('监听到gmi事件')
})
// 发射事件
setTimeout(() => {
emitter.emit('gmi')
}, 2000)取消监听
javascript
const EventEmitter = require('events')
// 创建EventEmitter实例
const emitter = new EventEmitter()
// 监听事件
function handleGmi() {
console.log('监听到gmi事件')
}
emitter.on('gmi', handleGmi)
// 发射事件
setTimeout(() => {
emitter.emit('gmi')
// 取消监听
emitter.off('gmi', handleGmi)
setTimeout(() => {
emitter.emit('gmi')
}, 100)
}, 2000)传递参数
javascript
const EventEmitter = require('events')
// 创建EventEmitter实例
const emitter = new EventEmitter()
// 监听事件
function handleGmi(...args) {
console.log('监听到gmi事件', args)
}
emitter.on('gmi', handleGmi)
// 发射事件
setTimeout(() => {
emitter.emit('gmi', 'gmi', 1, 6.1)
// 取消监听
emitter.off('gmi', handleGmi)
setTimeout(() => {
emitter.emit('gmi')
}, 100)
}, 2000)常见方法
EventEmitter 的实例有一些方法,可以记录一些信息:
emitter.eventNames():返回当前 EventEmitter 对象注册的事件字符串数组;emitter.getMaxListeners():返回当前 EventEmitter 对象的最大监听器数量,可以通过 setMaxListeners()来修改,默认是 10:emitter.listenerCount(事件名称):返回当前 EventEmitter 对象某一个事件名称,监听器的个数emitter.listeners(事件名称):返回当前 EventEmitter 对象某个事件监听器上所有的监听器数组;
javascript
const EventEmitter = require('events')
const ee = new EventEmitter()
ee.on('gmi', () => {})
ee.on('gmi', () => {})
ee.on('gmi', () => {})
ee.on('hn', () => {})
ee.on('hn', () => {})
// 1、获取所有监听事件的名称
console.log(ee.eventNames())
// 2、获取监听器最大的监听个数
console.log(ee.getMaxListeners())
// 3、获取某个事件名称对应的监听器个数
console.log(ee.listenerCount('gmi'))
console.log(ee.listenerCount('hn'))
// 4、获取某个事件名称对应的监听器函数(数组)
console.log(ee.listeners('gmi'))额外方法补充
emitter.once(eventName, listener): 事件监听一次emitter.prependListener(): 将监听事件添加到最前面emitter.prependOnceListener0): 将监听事件添加到最前面,但是只监听一次emitter.removeAllListeners([eventName]): 移除所有的监听器
javascript
const EventEmitter = require('events')
const ee = new EventEmitter()
// 1、事件监听只监听一次
ee.once('gmi', () => {
console.log('once监听gmi')
})
// 2、将监听事件添加到最前面
ee.prependListener('gmi', () => {
console.log('on监听gmi2')
})
ee.emit('gmi')
ee.emit('gmi')
ee.emit('gmi')
// 3、移除所有的监听器
// 不传递参数的情况下,移除所有事件名称的所有事件监听
// 在传递参数的情况下,只会移除传递的事件名称的事件监听
ee.removeAllListeners()
ee.removeAllListeners('gmi')三、Buffer 和字符串
Buffer 相当于是一个字节的数组,数组中的每一项对应一个字节的大小
javascript
// 1、创建Buffer
const buf = new Buffer('hello')
console.log(buf)
// 2、创建Buffer
const buf2 = Buffer.from('world')
console.log(buf2)
// 3、创建Buffer(字符串中包含中文)
const buf3 = Buffer.from('你好世界')
console.log(buf3)
// 4、手动指定的Buffer创建过程的编码
const buf4 = Buffer.from('哈哈哈', 'utf16le')
// 编码操作
console.log(buf4)
// 解码操作
console.log(buf4.toString('utf16le'))Buffer 的其他创建方式
JavaScript
// 1、创建一个Buffer对象
// 8个字节大小的buffer内存空间
const buf = Buffer.alloc(8)
console.log(buf)
// 2、手动对每个字节进行访问
console.log(buf[0])
console.log(buf[1])
// 3、手动对每个字节进行操作
buf[0] = 100
buf[1] = 0x66
console.log(buf)
console.log(buf.toString())Buffer 的创建过程
创建 Buffer 时,并不会频繁的向操作系统申请内存,它会默认先申请一个8*1024个字节大小的内存,也就是 8kb