流的四种类型
- 可读流
- 可写流
- Duplex:双工流 net.socket 比如聊天系统,既可以发送消息也可以接收消息
- transform:转换流 也算是双工流 如文件压缩 既可以读取数据也可以写入数据
stream 对象都是EventEmiter的实例,拥有data,end,error等方法
const fs = require('fs');
// 创建一个可读流数据
const rs = fs.createReadStream("demo.txt");
// 创建一个可写流数据
const ws = fs.createWriteStream("copy1.txt");
// 监听数据传输, 块 buffer 二进制
// 不停进行数据读取,触发data事件
// 可读流:两种模式,自动流动flowing模式 手动流动pushed stream.read();
rs.on("ready", ()=>{
console.log('the file is open');
})
// flowing mode
rs.on("data", chunk => {
console.log(chunk);
ws.write(chunk);
});
rs.on("error", error=>{
console.log('error:'+ error);
});
rs.on("close", ()=>{
console.log('the file is closed');;
});
rs.on("end", () => {
ws.end();
});
transform stream 转换流
继承自双工流 要求用户自己实现一个transform方法,进行数据转换
const stream = require("stream");
const transform = stream.Transform({
// 需要用户自己实现这个transform方法
transform(chunk, encoding, cb) {
// 大小写字母转换,push 到缓存区
this.push(chunk.toString().toLowerCase());
// 用户自己实现这个方法 需要进行一个回调
cb();
}
});
transform.write("HOLA MARISOL QUE TAL?");
console.log('transformed successfully! ',transform.read().toString());
pipe 管道 保证读写速度 方式数据丢失
// 通过pipe方法 就像是用一根管道来输送液体 不会出现数据丢失的问题
// pipe 只是可读流的方法 不要写反了
rs.pipe(ws);
读写的时候有一个缓存区,可以对缓存区的大小进行设置
// 设置一个缓冲区,大小默认16k,比如32k, 就会读取两次,每一次等缓存区满了之后再进行下一次
const rs = fs.createReadStream("data.txt",{
encoding: 'utf8', // 显示为字符串 莫认为二进制
highWaterMark: 6, // 单位byte 字节, 默认为16btye
})
链式流操作
类似于通过点点点的方式进行链式操作,是创建多个流进行操作的机制,常用于pipe操作
// 文件压缩
const fs = require('fs');
const zilb = require('zlib');
fs.createReadStream('data.txt')
.pipe(zilb.createGzip())
.pipe(fs.createWriteStream('data.txt.gz'))
console.log('finish');
const stream = require("stream");
const transform = stream.Transform({
transform(chunk, encoding, cb) {
// 大小写字母转换,push 缓存区
this.push(chunk.toString().toLowerCase());
cb();
}
});
transform.write("HOLA MARISOL QUE TAL?");
console.log('transformed successfully! ',transform.read().toString());
按行读取的最佳方案 readLine
比如很多日志文件都是分行的,最好是一行一行进行读取
// 示例,计算 log.txt 中http://1234.com访问次数
const fs = require('fs');
const path = require('path');
const readLine = require('readline');
const fileName = path.resolve(__dirname,"log.txt");
const readStream = fs.createReadStream(fileName);
const readL = readLine.createInterface({
// 输入
input: readStream
});
let count = 0;
readL.on('line', data => {
console.log(data);
if(data.indexOf('http://1234.com')>-1){
count++;
}
});
readL.on('close', () => {
console.log("读取完成", count);
});
在 stream中默认使用buffer 二进制
在i/o(input/output)操作中,数据格式未知,字符串、音频、网络包, asc编码 utf8编码
二进制无论那种格式都认识,而且效率非常高