系统性Node.js——手写文件流( 二 )
open() {fs.open(this.path, this.flags, (err, fd) => {if (err) {// 文件打开失败触发 error 事件this.emit('error', err)return}// 记录文件标识符this.fd = fd// 文件打开成功后触发 open 事件this.emit('open')})}
当打开文件后记录下文件标识符 , 即 this.fdreadread 方法如下:
read() {// 由于 ```fs.open``` 是异步操作,// 所以当调用 read 方法时 , 文件可能还没有打开// 所以我们要等 open 事件触发之后 , 再次调用 read 方法if (typeof this.fd !== 'number') {this.once('open', () => this.read())return}// 申请一个 highWaterMark 字节的 buffer ,// 用来存储从文件读取的内容const buf = Buffer.alloc(this.highWaterMark)// 开始读取文件// 每次读取时 , 都记录下文件的偏移量fs.read(this.fd, buf, 0, buf.length, this.offset, (err, bytesRead) => {this.offset += bytesRead// bytesRead 为实际读取的文件字节数// 如果 bytesRead 为 0 , 则代表没有读取到内容 , 即读取完毕if (bytesRead) {// 每次读取都触发 data 事件this.emit('data', buf.slice(0, bytesRead))// 如果处于流动状态 , 则继续读取// 这里当调用 pause 方法时 , 会将 this.flowing 置为 falsethis.flowing--tt-darkmode-color: #595959;">上述每行代码都有注释 , 相信也不难理解 , 这里有几个关键点要注意一下
- 一定要等文件打开后才能开始读取文件 , 但是文件打开是一个异步操作 , 我们并不知道具体的打开完毕时间 , 所以 , 我们会在文件打开后触发一个 on('open') 事件 , read 方法内会等 open 事件触发后再次重新调用 read()
- fs.read() 方法之前有讲过 , 可以从前文回顾里看一下 手写 fs 核心方法
- this.flowing 属性是用来判断是否是流动的 , 会用对应的 pasue() 方法与 resume() 来控制 , 下面我们来看一下这两个方法 。
pausepause() {this.flowing =false}
resumeresume() {if (!this.flowing) {this.flowing = truethis.read()}}
完整代码const { EventEmitter } = require('events')const fs = require('fs')class ReadStream extends EventEmitter {constructor(path, options = {}) {super()this.path = paththis.flags = options.flags ?? 'r'this.encoding = options.encoding ?? 'utf8'this.autoClose = options.autoClose ?? truethis.start = options.start ?? 0this.end = options.end ?? undefinedthis.highWaterMark = options.highWaterMark ?? 16 * 1024this.offset = this.startthis.flowing = falsethis.open()this.on('newListener', (type) => {if (type === 'data') {this.flowing = truethis.read()}})}open() {fs.open(this.path, this.flags, (err, fd) => {if (err) {this.emit('error', err)return}this.fd = fdthis.emit('open')})}pause() {this.flowing =false}resume() {if (!this.flowing) {this.flowing = truethis.read()}}read() {if (typeof this.fd !== 'number') {this.once('open', () => this.read())return}const buf = Buffer.alloc(this.highWaterMark)// const howMuchToRead = Math.min(this.end - this.start + 1, buf.length)fs.read(this.fd, buf, 0, buf.length, this.offset, (err, bytesRead) => {this.offset += bytesReadif (bytesRead) {this.emit('data', buf.slice(0, bytesRead))this.flowing--tt-darkmode-color: #595959;">文件可读流总结可以看到 , 我们用了不到 70 行代码就实现了一个可读流 , 所以原理其实并没有想象中那么难 , 相信大家也很容易就可以掌握 。
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 三星发布Galaxy Chromebook 2 配备QLED显示屏和特殊手写笔支持
- 开会再也不用手写,微信打开这个设置,会议纪要一键生成
- “记”兴之作 智能手写本推荐——柔宇RoWrite 2
- 为中端机配备手写笔!摩托罗拉G Stylus 2021渲染图曝光
- S Pen手写笔支持将为Galaxy Z Fold 3带来质变
- 三星暗示Galaxy S21系列将在明年1月发布:支持手写笔
- Vivo折叠屏智能机新专利曝光 带有手写笔专用收纳槽
- 三星确认Galaxy S21等手机将支持手写笔 Note系列面临被抛弃命运
- 外媒分享带新款S Pen手写笔的Galaxy S21 Ultra概念渲染图
- Galaxy S21 Ultra的疑问:三星将如何权衡曲面屏与S Pen手写笔?