概念

buffer存了什么

buffer是一个操作字节的对象,它的底层是一个字节数组,存储着16进制数字。

var str = 'hello buffer'
var buffer = new Buffer(str, 'utf-8')
console.log(buffer) //输出的是十六进数字

buffer的每个元素是16进制的两位数,也就是每个元素的大小是0-255.
因为 F X 16 + F X 16^0 = 255

溢出了怎么办

我们可以直接对buffer的元素进行赋值

var buffer = new Buffer(10)
buffer[0] = 300 
console.log(buffer[0])

如果赋的值是小数,小数部分会直接被舍弃。
溢出的时候,就是如果大于255就减去256直到小于255,如果小于0则加上256直到大于0

 if ( x > 255 ) {
     while(x > 255) {
       x = x - 256
     }
 }
 
 if ( x < 0 ) {
   x = x + 256
 }

补充:~~~~
负数在计算机里面存储的是补码,最高位为符号位(0为正,1为负),除符号位,其他位会取反,最低位取反后加1
如:-1
取反前: 1000 0001
取反: 1111 1110
末位加1:1111 1111
这样计算机读出来就是255啦

字符串与Buffer的转换

字符串跟buffer可以直接转换的编码类型有:
ASCII; UTF-8; UTF-16LE/UCS-2; Base64; Binary; Hex;

对于不支持的,可以用第三方库协助编码解码,常用的有:
iconv:调用c++实现,需要js到c++的切换,要消耗更多性能。
iconv-lite:纯Js实现,效率更高。

基本转换
  var buffer = new Buffer(str, [enconding])
  buffer.toString([enconding])
分段转换

注意同一段编解码要用同样的enconding

  var buffer = Buffer.write(str, [offset], [length], [enconding])
  
  buffer.toString([enconding], [start], [end])
库iconv/iconv-lite的使用

由于我们常用的GBK,GB2312都不在Buffer默认支持的编码列表中,我们需要借助第三方库进行编码解码。

实现 处理无法转换内容 总结
iconv-lite js实现 直接输出乱码 不需要从c++切换到js,性能比较好
iconv 调用c++实现 提供忽略或翻译处理 对乱码的处理比较完善
var iconv = require('iconv-lite');
var buffer = iconv.encode('床前明月光', 'GBK');
var str = iconv.decode(buffer, 'GBK')

buffer的拼接:乱码问题的解决

读取文件时,onData里面拿到的也是buffer,直接用加号拼接buffer,在长字节输入时,容易产生乱码。

var fs = require('fs')
var rs = fs.createReadStream('test.md', {highWaterMark: 11})
var data = ''
rs.on('data', function(chunk) {
    data += chunk
})
rs.on('end', function() {
    console.log(data) // 输出存在乱码,因为一个汉字3个字节,不能被11整除,第三个字只能由两个字节显示,会出现乱码
})

正确的拼接方式是用一个数组把每次读取的chunk存储起来,然后用buffer.concat生成一个合并的Buffer对象。

var fs = require('fs')
var iconv = require('iconv-lite');
var rs = fs.createReadStream('test.md', {highWaterMark: 11})
var chunks = []
var size = 0
rs.on('data', function(chunk) {
    chunks.push(chunk)
    size += chunk.length;
})
rs.on('end', function() {
    var buffer = Buffer.concat(chunks, size)
    var str = iconv.decode(buffer, 'utf-8')
    console.log(str)
})

buffer的性能优势

在网络传输中,如果先把传输的对象转换成buffer可以提高系统的性能。
对于文件操作,文件本身存储的就是二进制数据,所以在不需要改变文件内容的场景下,直接传输Buffer性能最好。另外highWaterMark的值会影响性能,highWaterMark设置过小,会导致读取次数过多,设置过大,又可能导致读取小文件的时候浪费内存空间(这个申请多了的内存还是可以给下一次读取使用)。对大问题的读取,设置比较大的highWaterMark可以提高性能。


supportlss
230 声望16 粉丝