看完这篇文章,你需要能解答以下问题:
1. buffer是什么?为什么要引入Buffer?
2. Stream用于处理什么?有哪些方法、API
stream是对buffer的高级封装,操作的底层还是buffer对象
stream继承自EventEmitter接口,可以实现对读写操作的监听
推荐阅读
buffer和stream的区别
- 二进制数据
- 计算中的数据类型,比如文字、图片、视频等,都是以0、1的形式存储在内存中。
- 字符集
- 定义一套规则,用数字表示常用的字符
- 常用的规则有:ASCII和 Unicode编码
- 字符编码
- 定义一套规则,规定如何用二进制形式,表示数字,即用多少位来表示数字,比如UTF-8
- utf-8规定用字节表示数据,一个字节用8位(bit)表示,即用8个0或1,表示一个字节
- stream
- buffer
- 等待区域—buffer,电脑中很小的一个物理地址,一般在内存中,数据在这里暂存
- 最后,在stream中,发送出去并处理
- 因此buffer,可以在stream中,对数据进行处理
Buffer:缓冲器
基础介绍
- Buffer在全局作用域中,无需使用require()
- Node无法操作二进制数据,因此无法直接对内存进行读写。
- JS只有字符串类型,没有二进制数据类型,因此Node提供和String对等的全局钩子函数Buffer实现对二进制数据的操作
- 读取文件,能够得到Buffer实例
- 也可以直接构造Buffer
new Buffer()
- Buffer解决Node支持二进制数据的问题,可以让node处理内存,如操作数据流、文件系统等
- 新版本Node中,创建BufferAPI:new Buffer()已经不被推荐使用了,改用 Buffer.from(array)
- 用途:让Node以数据流形式读取内存中的数据
- 数据流 一般不能一次性获取到,因此适合大数据的读取和不断返回chunk的外部源。
- 流的生产速度和消费者速度通常是不一致的,因此需要buffer暂存数据。
Buffer和字符串的转换
Buffer.from(str, ‘utf8’):字符串 ===> Buffer
buf.toString(‘utf8’): Buffer ===> string
buf.toJSON():Buffer ==> json
- 默认字符编码格式
- 字符编码
- 解码:Buffer转换为字符串
- 编码:字符串转换为Buffer
- 二进制转文本的编码:base64、hex
- 编码:Buffer转换为字符串
- 解码:字符串转换为Buffer
- Buffer实例也是JS的Uint8Array和 TypedArray实例,但有某些细微的不兼容
常用API
* 创建buffer
* Buffer.from()
* Buffer.alloc() | allocUnsafe() | allocUnsafeSlow
* alloc():默认用0填充,速度比其他两个慢,但也较为安全
* allocUnsafe:默认用之前预留的内存分配数据
* buffer格式转换
* buf.toJSON()
* buf.toString()
* 拷贝buffer
* buf.copy(target, targetStart, sourceStart, sourceEnd) === TypedArray.set
* copy():先创建新内存,然后将内存中的数据拷贝过去
* 裁剪buffer
* buf.slice()
* String是只读的,对字符串的改变,都是会得到一个新字符串
* 但Buffer是指针,更改某个位置的字节或slice()方法不会生成一个新Buffer,而是返回一个更改后的原Buffer
* Buffer.slice()不会返回一个新buffer,而是返回修改了后的原buffer指针
* buffer相等性判断:buf1.equals(buf2)
* 判断buffer是否包含特定值:includes、indexOf
* 清除Buffer:Buffer.fill(0)
* 释放buffer:buffer无法自动释放,只能靠V8的垃圾回收机制,但是我们可以解除对buffer的引用
Stream
- 处理Node中的流式数据,如http服务器的请求和 process.stdout都是流式数据
- Stream()操作,是基于事件机制的,继承自NodeJS提供的EventEmitter
流的类型—4种
- Writeable:可写数据流
- Readable:可读数据流
- Duplex:可写可读流
- Transform:读写过程中,可以互相转换的数据流
流操作的三种形式
- String | Buffer | 对象模式(除String外的其他类型,统称为对象模式)
- 将已经存在的流,切换为对象模式是不安全的。
- 可以利用objectMode选项,将流实例,切换为对象模式
缓冲
- 缓冲器中存在可写流和可读流,可利用writeable.writeableBuffer和 readable.readableBuffer获取
- highWateMark:缓冲器中可缓冲的数据大小,由流构造函数决定
- 普通模式的流:highWateMark--指定了字节总数
- 对象模式:highWateMark—指定对象总数
- 可读流
- stream.push():数据会被缓冲在可读流中
- stream.read():消费可读流
- 当达到highWateMark的阈值时,流会停止从底层资源读取数据,直到当前缓冲的数据被消费
- 可写流
- writeable.wrte()时:数据会被缓冲在可写流中
- 当highWateMark达到阈值时,调用writeable.write()方法会返回false,否则返回true
- Stream.pipe():解决写入和读取速度不一致时,造成的爆仓问题
- Duplex和Transform:各自维护这两个相隔独立的内部缓冲器,用于读取和写入。两边都可以独立运作
消费流
- 可写流:比如http请求,http的响应
- 方法:write() | end()
- 事件:close | finish | error | drain | pipe | unpipe
- 可读流
- 方法:destroy() | pause() | pipe() | read() | resume()
- 事件:close | data | end | pause | resume
- 当写入速度跟不上读取速度时,只写数据流内部的缓存会爆仓
- .write()方法返回boolean值判断传入的数据,是写入目标,还是临时放入缓存了
- .drain()事件判断只写数据流已经将缓存中的数据写入目标,可以继续工作了
- .resume()继续传递数据
- .pipe()方法可以直接解决上面的爆仓问题,pipe的内部实现方式和上面的代码类似
- 双工流和转换流
实现流--待补充