Node.js Stream 详解之编码篇

经过流中转的数据,可能会经历编码转换。 本文介绍可读流和可写流中一些常见的编码转化情况。

假定 options 为创建流时传给 ReadableWritable 的配置。 正常情况下,流只处理 String 和 Buffer 类型的数据,但可以设置options.objectMode,使流能处理任意类型的数据。 此时,称流处于对象模式(object mode)。

Node.js Stream 详解之编码篇

下面是一个编码转化的例子:

var buf = new Buffer('YWJj', 'base64')

console.log('Binary:', buf)

// Binary: <Buffer 61 62 63>

console.log('Base-64:', buf.toString('base64'))

// Base-64: YWJj

console.log('UTF-8:', buf.toString('utf8'))

// UTF-8: abc

数据从String类型转化成Buffer类型称为编码,实际是得到字符串在指定编码方式下的二进制表示。

Buffer类型转化成String类型则称为解码,实际是将二进制根据指定编码翻译成字符串。

如果编码和解码指定的编码方式不一样,就实现了一次编码转换。 譬如上面的YWJjabc便是一次从Base-64到UTF-8的编码转换。 这样的现象,也会出现在流操作数据的过程中。

可读流

外界与可读流的数据沟通是通过push(data, encoding)on('data', chunk => {})来实现的。 本小节研究data, chunk, encodingoptions.encoding,以及options.objectMode之间的关系。

对输入进行编码

push方法未指定encoding时,默认使用options.defaultEncoding。后者的默认值是'utf8'。 所以,可以认为encoding一定有值。

在非对象模式下,添加到流中的文本会进行一次编码。

const stream = require('stream')

const source = ['YWJj', 'ZGVm']

const readable = stream.Readable({

read: function () {

const data = source.length ? source.shift() : null

this.push(data, 'base64')

}

})

readable.on('data', data => console.log(data))

输出:

<Buffer 61 62 63>

<Buffer 64 65 66>

在上面的例子中,encoding 值为 'base64'。 所以 'YMJj' 与 'ZGVm' 以 Base-64 的编码方式表示,被输出。

对输出进行解码

在前小节的例子中,可以通过设置options.encoding来对输出进行解码:

const stream = require('stream')

const source = ['YWJj', 'ZGVm']

const readable = stream.Readable({

encoding: 'utf8',

read: function () {

const data = source.length ? source.shift() : null

this.push(data, 'base64')

}

})

readable.on('data', data => console.log(data))

输出:

abc

def

由于options.encoding设置为'utf8',所以,'YMJj''ZGVm'的二进制表示均按照UTF-8的编码方式进行解码再输出。

可见,encoding控制对输入进行编码,而options.encoding控制对输出进行解码。 如果encoding等于options.encoding,这两步其实都不会发生,也没必要发生。

chunk实际是data编码转换后的结果。

对象模式下接受任意类型的输入

如果设置options.objectModetrue,则data可以是任意类型,流不再对输入进行编码。

但是如果指定了options.encoding,且push方法未指定encoding,则输出前仍然会进行解码。

const stream = require('stream')

const source = ['YMJj', Buffer('ZGVm'), {}]

const readable = stream.Readable({

objectMode: true,

encoding: 'utf8',

read: function () {

const data = source.length ? source.shift() : null

this.push(data)

}

})

readable.on('data', chunk => console.log(chunk))

输出:

YMJj

ZGVm

[object Object]

试图对StringBuffer以外的数据类型进行解码(调用toString()),其结果通常不是所预期的。

如果不设置options.encoding,则结果将为:

YMJj

<Buffer 5a 47 56 6d>

{}

可写流

外界与可写流的数据沟通是通过write(data, encoding)_write(chunk, enc, next)来实现的。 本小节研究data, chunk, encodingencoptions.objectMode,以及options.decodeStrings之间的关系。

与可读流相比,没有了options.encoding,意味着chunk不再是解码的结果。

readable.pushwritable.write都是往流中添加数据,push方法会使数据经历编码和解码两个步骤再输出,但write只有编码这一个环节。 事实上Writable不能设置options.encoding

所以,如果不是对象模式,chunk一定是Buffer对象,_write中的enc值一定是buffer

const stream = require('stream')

const source = ['YWJj', 'ZGVm']

const writable = stream.Writable({

write: function (chunk, enc, next) {

console.log(chunk, enc)

next()

}

})

writable.write(source[0], 'base64')

writable.write(source[1], 'base64')

writable.end()

输出:

<Buffer 61 62 63> 'buffer'

<Buffer 64 65 66> 'buffer'

enc表示对data进行何种转化得到chunk

对象模式:

const stream = require('stream')

const source = ['abc', Buffer('def')]

const writable = stream.Writable({

objectMode: true,

write: function (chunk, enc, next) {

console.log(chunk, enc)

next()

}

})

writable.write(source[0])

writable.write(source[1])

writable.end()

输出:

abc utf8

<Buffer 64 65 66> 'buffer'

以上是 Node.js Stream 详解之编码篇 的全部内容, 来源链接: utcz.com/z/264107.html

回到顶部