Node之IO

作者: 人失格 | 来源:发表于2017-09-07 20:49 被阅读41次

    Buffer

    Buffer的构成

    Buffer对象类似数组,它的元素位16进制的两位数,即0到255的数值。主要是用来存储二进制的数据

    const buf = Buffer.from('Hello world')
    

    初始化Buffer会随机的填充了0到255的随机值

    var buffer = new Buffer(100);
    buffer[20] = -100;
    
    console.log(buffer[20]) // 如果存储的数字小于0或者大于255则直接加值256知道值位于0到255之间
    

    Buffer的底层分配

    Node从c++层面申请内存,在JS层面用来分配内存的策略,Buffer在C++申请内存主要是8K。

    Buffer的转换

    目前Buffer的对象是可以直接与字符串进行互相转换,目前支持的字符串编码类型有

    • ASCII

    • UTF-8

    • UTF-16

    • Base64

    • Binary

    • Hex

      目前官方暂时不支持汉字编码GBK之类,如果有类似的汉字编码需求需要调用第三方库的支持。

    Buffer的乱码现象

    因为Buffer对象只要是用于二进制与字符串的转换,一旦设计编码 解码就会出现所谓的乱码现象,特别是出现在汉字编码问题。

    var rs = fs.createReadStream('buffer.txt',{
      highWaterMark:11
    });
    
    var data = '';
    rs.on('data',(thunk)=>{
      data +=thunk; // data.toString() += thunk.toString()
    })
    
    rs.on('end',()=>{
      console.log(data);
    })
    
    

    在Options上选择了highWaterMark,主要是影响操作系统读取文件的字节块,目前是按照11字节读取,因为汉字在UTF-8中编码只要是三个字节,所以在读取汉字的时候可能会出现两个字节导致无法编码,出现所谓的乱码现象。

    乱码解决方案

    • stream.setEncoding('utf-8') 这样当stream读取到中文汉字需要解码的时候 底层的string_decoder 则会收集完整的字节然后解码显示汉字
    • 通过将stream中的数据接受完整数据后,然后指定编码符来统一解码。

    Stream

    Node.js中有四种基本的流类型:

    • Readable 可读的流(例如 fs.createReadStream())
    • Writable 可写的流 (例如 fs.createWriteStream())
    • Duplex 可读写的流 ( 例如 net.Socket)
    • Transform 在读写过程中科院修改和变换数据的Duplex流

    缓冲

    Writable和Readable流都会将数据存储到内部的缓存中。这些缓存可以通过相应的writable._writableState.getBuffer()或者readable._readableState.buffer来获取。 缓存的大小取决流构造函数的highWaterMark选项。对于普通的流, highWaterMark选项指定了总共的字节数。对于工作在对象模式的流,highWaterMark指定了对象的总数。

    • 当可读流实现调用了stream.push(chunk)方法,数据被放到了缓存中,如果流的消费者没有调用stream.read()方法,这些数据会始终存在内部队列,直到被消费。
    • 可写流通过反复调用writable.write(chunk)方法将数据放到缓存。当内部可写入缓存的总大小小于highWaterMark指定的阀值,调用writable.write()将返回true.
    • streamAPI的关键方法在于stream.pipe()方法,就是限制缓存数据大小,以达到可接受的程度。这样,对于读写速度不匹配的源头和目标。

    可写流

    Write Streams 是destination的一种抽象,这种destination允许数据写入

    Writable的例子包括了

    • HTTP request, on the client
    • HTTP response, on the server
    • fs write streams
    • lib streams
    • crypto streams
    • TCP sockets
    • child process stdin

    Writeable流暴露了一些方法 比如write() end() pipe()方法

    Writable类的事件和方法

    • close事件 底层资源关闭后触发 close事件触发后,该流将不会再触发任何事件
    • drain 事件 当stream.write(chunk)方法返回false 出发 此时才能继续让缓冲区写入数据
    • error事件 stream写入数据出错
    • finish 事件 stream.end()方法
    • pipe 事件 输出到目标可写入流的源流 stream.pipe() 方法
    • writable.cork() 强制将所有写入数据源都放入内存中的缓冲区
    • writable.end(chunk, encoding, callback)
    • writable.setDefaultEncoding
    • writable.write(chunk,encoding,callback)
    • writable.destroy(error)

    可读流

    Readable的例子

    • HTTP response, on the client
    • HTTP request , on the server
    • fs read streams
    • zlib streams
    • crypto streams
    • TCP sockets
    • child process stdin

    可读流的时间和方法

    • close事件
    • data事件
    • end事件
    • error事件
    • readable.pause()
    • readable.pipe()
    • readable.unpipe()
    • readable.setEncoding(encoding)
    • readable.destory(error)

    两种模式

    可读流事实上工作在下面两种模式之一: flowing 和paused

    在flowing模式下,可读流自动从系统底层读取数据,并通过EventEmitter接口的事件尽快将数据提供给应用

    在paused模式下,必须显示调用stream,read()方法来从流中读取数据片段

    所有初始工作位paused的Readable流,可以通过下面三种途径切换到flowing模式:

    • 监听了'data'事件
    • 调用了stream.resume()方法
    • 调用了stream.pipe()方法将数据发送Writable

    从Flowing模式切换到paused模式

    • 如果存在了管道目标,可以通过取消'data'事件箭筒,并调用stream.unpipe()方法移除所有管道目标来实现
    • 如果不存在管道目标,直接调用stream.pause()方法来实现

    三种状态

    任意可读流应确切处于下面三种状态:

    • readable._readableState.flowing = null

      由于不存在数据消费者,可读流将不会产生数据

    • readable._readableState.flowing = false

      调用 readable.pause() 方法, readable.unpipe() 方法, 或者接收 “背压”(back pressure), 将导致 readable._readableState.flowing 值变为 false。 这将暂停事件流,但 不会 暂停数据生成。

    • readable._readableState.flowing = true

      当stream监听了 'data'事件 调用了pipe方法,或者调用readable.resume()方法

    相关文章

      网友评论

        本文标题:Node之IO

        本文链接:https://www.haomeiwen.com/subject/dblwjxtx.html