Node之IO

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()方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • stream 流是一个抽象接口,在 Node 里被不同的对象实现。例如 request to an HTTP se...
    明明三省阅读 3,392评论 1 10
  • 流是Node中最重要的组件和模式之一。在社区里有一句格言说:让一切事务流动起来。这已经足够来描述在Node中流...
    宫若石阅读 543评论 0 0
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 6,305评论 0 6
  • 为什么应该使用流 你可能看过这样的代码。 这段代码中,服务器每收到一次请求,就会先把data.txt读入到内存中,...
    饥人谷_xxxxx阅读 10,791评论 1 12
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,600评论 18 139