概念
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可以提高性能。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。