nodejsbuffer-基础篇

65次阅读

共计 1999 个字符,预计需要花费 5 分钟才能阅读完成。

概念

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 可以提高性能。

正文完
 0