【NODE.JS】Buffer

Buffer是一个Array的对象,主要用于操作字节。

目录

1. 模块结构

2. Buffer对象

3. Buffer内存分配

4. Buffer的转换

5. Buffer的拼接

6. 正确拼接Buffer


1. 模块结构

Buffer是一个的JavaScript与C++结合的模块。性能相关的部分由C++实现,非性能相关的部分用JavaScript实现。

 Buffer所占的内存不是通过V8分配的,属于堆外内存。

Node在进程启动时就家长了Buffer,并将其放置在全局对象上,所以无需require() 直接使用。

2. Buffer对象

其类似数组,元素为16进制的两位数,即0到255的数值

可以通过访问length属性得到长度,同时可以通过下标访问元素

如果元素赋值小于0,就将该值逐次加到256,直到得到一个0到255之间的整数。

如果大于255,就逐次减256,直到得到0到255区间内的值

如果是小数,则舍弃小数部分,只保留整数部分

3. Buffer内存分配

Buffer对象的内存分配不是在V8中的堆内存中,而是在Node的C++层面实现内存的申请的。

Node在内存使用上应用的是在C++层面申请内存、在JavaScript中分配内存的策略。

slab分配机制

一种动态内存管理机制,slab就是一块申请好的固定大小的内存区域,具有三种状态

full:完全分配状态

partial:部分分配状态

empty:没有被分配状态

 

4. Buffer的转换

Buffer对象可以与字符串之间相互转换:

ASCII、UTF-8、UTF-16LE/UCS-2、Base64、Binary、Hex

(1)字符串转Buffer

通过构造函数完成

new Buffer(str, [encoding]);

一个Buffer对象可以存储不同编码类型的字符串转码的值,可以调用write()方法实现

buf.write(string, [offset], [length], [encoding])

(2)Buffer转字符串

buf.toString([encoding], [start], [end])

 可以设置endcoding,start、end三个三参数实现整体或者局部的转换

(3)Buffer不支持的编码类型

由于支持的编码类型有限, 可以使用以下方法判断是否支持转换

Buffer.isEncoding(encoding)

将编码类型输入,就可以知道是否支持转换,对于不支持的编码可以使用 iconv 和 iconv-lite两个模块支持。

iconv-lite 采用纯JS实现,iconv通过C++调用libiconv库实现

前者比后者更加轻量,无须编译和处理环境依赖直接使用。

5. Buffer的拼接

var fs = require('fs');

var rs = fs.createReadSteam('test.md');
var data = '';

rs.on("data", funciton (chunk){
    data += chunk;
});

rs.on("end", funciton (){
    console.log(data);
})

 正常读取字符流的过程,但是在英文环境中是没有问题的,在中文环境中会出现问题。

因为 

data += chunk;

实际上执行或者等价的代码是

data = data.toString() + chunk.toString();

所以当我们如果限制每次读取的Buffer长度时,就有可能在读取中文时出现乱码,最简单的解决办法就是提高每一次读取的长度,长度越大出现的概率越低

同时可以通过设置编码的方法

readable.setEncoding(encoding)

此方法在被调用时,可读流对象内部设置了一个decoder对象。

每次data事件都通过该decoder对象进行Buffer到字符串的解码,然后传递给调用者。

通过setEncoding() 的方式不可否认能解决大部分的乱码问题,但并不能从根本上解决该问题。

6. 正确拼接Buffer

淘汰掉setEncoding() 方法后,剩下的解决方案只有将多个小Buffer对象拼接为一个Buffer对象,然后通过iconv-tite一类的模块来转码方式。+=的方式显然不行,正确的Buffer拼接方法应该如下面展示的形式:

var chunks = [];
var size = 0;
res.on('data', function (chunk){
    chunks.push(chunk);
    size += chunk.length;
});

res.on('end', funciton (){
    var buf = Buffer.concat(chunks, size);
    var str = iconv.decode(buf, 'utf8');
});

正确的拼接方式是用一个数组来存储接收到的所有Buffer片段并记录下所有片段的总长度,然后调用Buffer.concat() 方法生成一个合成的Buffer对象。Buffer.concat() 方法封装了从小Buffer对象向大Buffer对象的复制过程, 实现过程十分细腻,值得围观学习:

Buffer.concat = funcion(list, length){
    if(!Array.isArray(list)) {
        throw new Error('Usage: Buffer.concat(list, [length])');
    }

    if(list.length === 0) {
        return new Buffer(0);
    }else if (list.length === 1) {
        return linst[0];
    }

    if (typeof length !== 'number') {
        length = 0;
        for(var i = 0; i < list.length; i++) {
            var buf = list[i];
            length += buf.length;
        }
    }

    var buffer = new Buffer(length);
    var pos = 0;
    for (var i = 0; i < list.length; i++) {
        var buf = list[i];
        buf.copy(buffer, pos);
        pos += buf.length;
    }

    return buffer;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值