Javascript 作为一个前段开发语言,只能做一些简单的字符串操作或DOM操作就可以满足业务需求。然而在nodejs应用中,需要处理网络协议、操作数据库、处理图片、接收上传文件等。因此Javascript的自有得字符串操作不能满足需求,于是buffer对象应用而生。
1. 创建buffer 实例
Buffer 对象在Node进程启动时就已经加载,并将他放在全局对象(global)上。所以在使用buffer时无需通过require加载既可直接使用。
var buf = new Buffer("I am spursyy."); //new Buffer 构造函数存在安全问题已经废弃
var buf = Buffer .copy("I am spursyy.") // 由Buffer.copy() 取代
常用构造函数:
A. Buffer.alloc(size[, fill[, encoding]])
size <Integer> 新建的 Buffer
期望的长度
fill
<String> | <Buffer> | <Integer> 用来预填充新建的 Buffer
的值。 默认: 0
encoding
<String> 如果 fill
是字符串,则该值是它的字符编码。 默认: 'utf8'
B. Buffer.allocUnsafe(size)
size
<Integer> 新建的 Buffer期望的长度
以这种方式创建的 Buffer实例的底层内存是未初始化的。 新创建的 Buffer
的内容是未知的,且可能包含敏感数据。 可以使用 buf.fill(0)
初始化 Buffer
实例为0。
C. Buffer.allocUnsafeSlow(size)
size
<Integer> 新建的 Buffer期望的长度
以这种方式创建的 Buffer实例的底层内存是未初始化的。 新创建的 Buffer的内容是未知的,且可能包含敏感数据。 可以使用 buf.fill(0)
初始化 Buffer
实例为0。
2. Buffer 内存的分配
Buffer 对象的内存分配不是在V8的堆内存中,而是在Node的C++层面实现内存的申请。因为处理大量数据不能采用需要一点内存就像操作系统申请一点内存的方式,这样大量内存的申请,对操作系统有很大的压力。
Buffer模块会预分配一个大小为 Buffer.poolSize 的内部 Buffer实例作为快速分配池。
Buffer.alloc(size, fill) 和 Buffer.allocUnsafe(size).fill(fill)的关键区别在于如果 size 小于或等于Buffer.poolSize的一半,则 Buffer.alloc(size, fill)不会使用这个内部的 Buffer 池,而 Buffer.allocUnsafe(size).fill(fill)会使用这个内部的 Buffer 池。 当应用程序需要 Buffer.allocUnsafe() 提供额外的性能时,这个细微的区别是非常重要的。
当使用 Buffer.allocUnsafe() 分配新建的 Buffer 时,当分配的内存小于 4KB 时,默认会从一个单一的预分配的 Buffer 切割出来。 这使得应用程序可以避免垃圾回收机制因创建太多独立分配的 Buffer实例而过度使用。 这个方法通过像大多数持久对象一样消除追踪与清理的需求,改善了性能与内存使用。
在开发者可能需要在不确定的时间段从内存池保留一小块内存的情况下,使用 Buffer.allocUnsafeSlow() 创建一个非池的 Buffer 实例然后拷贝出相关的位元是合适的做法。如下官网实例:
// 需要保留一小块内存块
const store = [];
socket.on('readable', () => {
const data = socket.read();
// 为保留的数据分配内存
const sb = Buffer.allocUnsafeSlow(10);
// 拷贝数据进新分配的内存
data.copy(sb, 0, 0, 10);
store.push(sb);
});
3. Buffer 的拼接
Buffer 的应用场景中,通常是以一段一段的方式传输数据。以下是实现代码:
var fs = require('fs')
var rs = fs.createReadStream('text.txt')
var data = ''
rs.on("data", function(chunk) {
data += chunk
})
rs.on("end", function() {
console.log(data)
})
如果将每次读取Buffer的长度设置为11,读的一旦是中文字符就会出现乱码的问题。
var rs = fs.createReadStream('text.txt', {highWaterMark: 11})
解决方案1, 给可读流设置编码
var rs = fs.createReadStream('text.txt', {highWaterMark: 11})
rs.setEncoding('utf8')
解决方案2, 使用concat() 函数拼接字符串
var fs = require('fs')
var rs = fs.createReadStream('text.txt')
var chunks = []
var size = 0
rs.on("data", function(chunk) {
chunks.push(chunk)
size += chunk.length
})
rs.on("end", function() {
var buf = Buffer.contact(chunks, size)
})