stream模块

  • 官方文档

  • streamNode.jsfs模块提供的又一个仅在服务区端可用的子模块,目的是支持“流”这种数据结构。

  • 什么是流?流是一种抽象的数据结构。想象水流,当在水管中流动时,就可以从某个地方(例如自来水厂)源源不断地到达另一个地方(比如你家的洗手池)。我们也可以把数据看成是数据流,比如你敲键盘的时候,就可以把每个字符依次连起来,看成字符流。这个流是从键盘输入到应用程序,实际上它还对应着一个名字:标准输入流(stdin)。

  • 数据流就是数据不是一次性全部返回或者一次性全部读取的,他是通过先读取(或者写入)一部分,再读取(或者写入)一部分,知道最后完成数据的全部操作的,因此stream模块更加适用于大型数据的读取或者写入操作

  • 如果应用程序把字符一个一个输出到显示器上,这也可以看成是一个流,这个流也有名字:标准输出流(stdout)。流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。

  • 有些流用来读取数据,比如从文件读取数据时,可以打开一个文件流,然后从文件流中不断地读取数据。有些流用来写入数据,比如向文件写入数据时,只需要把数据不断地往文件流中写进去就可以了。

  • Node.js中,流也是一个对象,我们只需要响应流的事件就可以了:data事件表示流的数据已经可以读取了,end事件表示这个流已经到末尾了,没有数据可以读取了,error事件表示出错了。

代码展示:

  • 读取数据流(readStream可读流.js)
// nodejs内置模块:stream(文件流操作) - createReadStream(文件可读流)

// 1.引入fs模块
const fs = require('fs')

// 2.创建文件可读流(里面接受两个参数:要读取的文件路径,读取的格式)
const rs = fs.createReadStream('./1.txt' , 'utf-8')

// 3.设置监听事件实现数据传输
rs.on('data' , (chunk)=>{
console.log(`数据正在传输:...`);
console.log(chunk);
})

// 4.数据传输完成
rs.on('end' , ()=>{
console.log(`数据传输完成!!`);
})

// 5.数据传输失败
rs.on('error' , (err)=>{
console.log(`数据传输失败,失败信息为:${err}`);
})

/*
要注意,`data`事件可能会有多次,每次传递的`chunk`是流的一部分数据。
要以流的形式写入文件,只需要不断调用`write()`方法,最后以`end()`结束:
*/
  • 写入数据流(writeStream可写流.js)
// nodejs内置模块:stream(文件流操作) - createWriteStream(文件可写流)

// 1.引入fs模块
const fs = require('fs')

// 2.创建文件可写流(里面接受两个参数:要写入的文件路径,写入的格式)
const wsl = fs.createWriteStream('./2.txt' , 'utf-8')

// 3.掉用write实现数据的写入
wsl.write('111')
wsl.write('222')
wsl.write('333')

// 4.最后调用end来结束文件的写入
wsl.end()

/*
要注意,`data`事件可能会有多次,每次传递的`chunk`是流的一部分数据。
要以流的形式写入文件,只需要不断调用`write()`方法,最后以`end()`结束:
*/
  • 管道连接读写数据流(pipe管道连接流.js)
// nodejs内置模块:stream(文件流操作) - pipe(文件可写流)

/*
pipe 顾名思义是管道的意思,这个方法能 可读流 和 可写流 连在一起
更加简单的实现数据的读写复制,能将一个文件里面的内容很简单的就复制到另一个文件
*/

// 1.首先导入fs模块
const fs = require('fs')

// 2.创建可读流和可写流
const rs = fs.createReadStream('./1.txt', 'utf-8')//创建可读流(数据的导出源)
const wsl = fs.createWriteStream('./2.txt' , 'utf-8')//创建可写流(数据的导入源)

// 3.使用pipe管道将两个源头接起来(读取到的 => pipe => 写入)
rs.pipe(wsl)//实现将 1.txt 里面的内容写入到 2.txt 中去

  • pipe 就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个Readable流和一个Writable流串起来后,所有的数据自动从Readable流进入Writable流,这种操作叫pipe
  • Node.js中,Readable流有一个pipe()方法,就是用来干这件事的。
  • 让我们用pipe()把一个文件流和另一个文件流串起来,这样源文件的所有数据就自动写入到目标文件里了,所以,这实际上是一个复制文件的程序

zlib模块

浏览器解析页面的大致流程如下:

image

  • 由此可见,如果文件过大从webserver到浏览器的传输时间就会很长所以我们可以先将文件压缩成gzip文件再进行传输。

代码展示:

// nodejs内置模块:zlib(文件压缩)
/*
要知道浏览器的解析过程是:
html源码 =(解析)> WebServer =(传递)> 浏览器 =(渲染)> 渲染到页面上

如果文件过大从webserver到浏览器的传输时间就会很长,导致页面出现延迟卡顿
这就会很影响用户的实际使用体验,因此我们可以先将文件压缩成gzip文件再进行传输
而压缩成gzip文件的方法就包含在zlib模块中
*/

// 1.首先导入相对应的模块
const http = require("http")//http模块用于创建服务器
const fs = require("fs")//fs模块用于操作文件
const zlib = require("zlib")//zlib模块用于压缩文件

// 2.创建gzip压缩
const gzip = zlib.createGzip()

// 3.创建服务器
http.createServer((req, res) => {
// 4.创建文件的可读流
const readStream = fs.createReadStream("./index.txt")
// 5.设置响应头文件
res.writeHead(200, { "Content-Type": "application/x-javascript;charset=utf-8","Content-Encoding":"gzip"})
// 6.使用pipe管道将可读流与页面渲染连通起来,让文件能够输出到页面当中
readStream.pipe(gzip).pipe(res)//res本身就是一个可写流

}).listen(3000, () => {
console.log("服务器启动成功,端口号3000正在监听....")
})


结果展示:

  • 使用zlib压缩前
    image

  • 使用zlib压缩后
    image

path模块

  • 官方文档

  • path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。

  • 例如:

    • path.join() 方法,用来将多个路径片段拼接成一个完整的路径字符串
    • path.basename() 方法,用来从路径字符串中,将文件名解析出来
    • path.extname()方法 获取文件的拓展名,即后缀名

代码展示:

  • path.join()进行路径的拼接.js
//首先导入相对应的模块
const path = require('path')
const fs = require('fs')

// 注意: ../ 会抵消前面的路径
const pathStr = path.join('/a', '/b/c', '../../', './d', 'e')// a/b/e
console.log(pathStr) // \a\b\d\e

// 注意:今后凡是涉及到路径拼接的操作,都要使用 path.join() 方法进行处理。不要直接使用 + 进行字符串的拼接。
// fs.readFile(__dirname + '/files/1.txt')

fs.readFile(path.join(__dirname, './files.txt'), 'utf8', function(err, dataStr) {
if (err) {
return console.log('文件读取失败!')
}
console.log('文件读取成功!' + '\n' + dataStr)
})
  • 结果展示:
    image

  • path.basename()读取文件名.js

// 使用 path.basename() 方法,可以获取路径中的最后一部分,经常通过这个方法获取路径中的文件名
//导入path模块
const path = require("path");

// 语法格式如下:
// path.basename(path[,ext])

// 参数解读:
// path : 必选参数,表示一个路径的字符串,一定是要字符串,最好有一个变量代替
// ext : 可选参数,表示文件扩展名
// 返回: <string> 表示路径中的最后一部分

// 例子:

const a = path.join(__dirname , './path路径模块初识.html');

const newPath = path.basename(a , '.html');
console.log(newPath);//只有 path路径模块初识 , 无后缀.html了
  • 结果展示
    image

  • path.extname()获取拓展名.js

// path.extname() 只获取文件的拓展名,即后缀名
// 语法格式
// path.extname(path)
// 参数解析
// path <string>必选参数,表示一个路径的字符串
// 返回: <string> 返回得到的扩展名字符串

// 例子
const path = require('path');

const a = path.join(__dirname , './path路径模块初识.html');

const name = path.extname(a);

console.log(name);//.html 只有后缀名
  • 结果展示:
    image