学习笔记—Buffer的常⽤⽅法与实现
⽇常的学习笔记,包括 ES6、Promise、Node.js、Webpack、http 原理、Vue全家桶,后续可能还会继续更新 Typescript、
Vue3 和常见的⾯试题等等。
Buffer
参考⽂献
缓冲区Buffer是暂时存放输⼊输出数据的⼀段内存。JS没有⼆进制数据类型,⽽在处理TCP和⽂件流的时候,必须要处理⼆进制数据。所以Node提供了⼀个Buffer对象来提供对⼆进制数据的操作。
Buffer表⽰固定内存分配的全局对象,也就是说要放到缓存区中的字节数需要提前确定。⽽Buffer好⽐由⼀个8位字节组成的数组,可以有效的在JavasScript中表⽰⼆进制数据。
Buffer简单来说就是node中的16进制,但Buffer在内存的标识也会全部使⽤2进制来进⾏表⽰。
(注:⽬前以⽆法使⽤new Buffer()创建 Buffer 实例,会存在安全性等问题。已被禁⽌使⽤。)
Buffer.alloc
Buffer代表的是内存,⼀旦声明好,就不能进⾏更改。
如果想要更改Buffer的⼤⼩,改⼩则对内存进⾏截取。改⼤的话就需要创建⼀个更⼤的内存空间,将数据拷贝进⾏,也就是我们俗称的扩容。
这时候就可以⽤到Buffer类的内置⽅法,Buffer.alloc()。
Buffer.alloc(size[, fill[, encoding]]),表⽰分配size个字节的新Buffer。如果fill为undefined,则Buffer将以零填充。
size:新的Buffer所需的长度。
fill:⽤于预填充新Buffer的值,默认值为0。
encoding:如果fill是字符串,则这就是它的编码。默认值为utf8。
// 创建了⼀个指定长度的buffer实例
let buf1 = Buffer.alloc(3); // 最⼩单位是 3字节
console.log(buf1); // <Buffer 00 00 00>
let buf2 = Buffer.alloc(6); // 单位是 6
console.log(buf2); // <Buffer 00 00 00 00 00 00>
Buffer.from
上⼀篇⽂章中,我们曾经使⽤Buffer.from来创建过。
Buffer.from⽅法⽤于创建包含指定字符串,数组或buffer的新Buffer实例。
Buffer.from可以传⼊的参数有很多,这⾥我们只扩展字符串和数组两种。
Buffer.from(array)
Buffer.from(array)使⽤0 – 255范围内的字节array分配新的Buffer。该范围之外的数组条⽬将被截断以符合它。
let buf1 = Buffer.from([0xe8, 0x8e, 0xab])
console.log(buf1); // <Buffer e8 8e ab>
let buf2 = Buffer.from([256, 0x8e, 0xab]) // 超过长度会⾃动取余
console.log(buf2); // <Buffer 00 8e ab>
let buf2 = Buffer.from(['aaa', 0x8e, 0xab]) // 不能在数组内存放其他数据类型
console.log(buf2); // <Buffer 00 8e ab>
(注:很少使⽤这种⽅法来定义buffer,因为需要指定存放的内容)
Buffer.from(string)
Buffer.from(string[, encoding])创建包含string的新Buffer。encoding参数标识将string转换为字节时要使⽤的字符编码。
string:要编码的字符串。
encoding:string的编码,默认值为utf8。
let buf = Buffer.from('莫⼩尚');
console.log(buf); // <Buffer e8 8e ab e5 b0 8f e5 b0 9a>
Buffer.from(string)是⽬前Buffer经常使⽤的⽅法。这个⽅法可以存储数据,存储的数据可以⽤Buffer进⾏表⽰。同时也可以和字符串之间进⾏相
互转化。
// 使⽤ .toString() ⽅法,将buffer转换成字符串
console.String()); // 莫⼩尚
// 可以转换成任意指定编码
console.String('base64')); // 6I6r5bCP5bCa
我们在进⾏读写操作时,如果不指定编码,则所有读取的⽂件内容都是buffer类型。
//
123456789
// index.js
const fs = require('fs');
let r = fs.readFileSync('./'); // 不指定 utf-8 编码格式
console.log(r); // <Buffer 31 32 33 34 35 36 37 38 39>
Buffer的扩容
我们在操作Buffer时,会遇到原本规定的内存⼤⼩不够的情况,这样我们就需要对Buffer进⾏扩容。
const buf1 = Buffer.from('莫')
const buf2 = Buffer.from('⼩尚')
const bigBuf = Buffer.alloc(buf1.length + buf2.length);
console.log(bigBuf); // <Buffer 00 00 00 00 00 00 00 00 00>
buf.length返回buf中的字节数。
这样我们就创建了⼀个更⼤的Buffer对象,现在我们需要将内容拷贝到这个⼤buffer中。
console.String()); // 莫⼩尚
这⾥我们使⽤到了py()⽅法,稍后会进⾏讲解。
这样我们就完成了⼀个简单的扩容操作。(注:在实际⼯作中,此⽅法并不常⽤。我们⼀般会使⽤at来进⾏扩容操作。)const buf1 = Buffer.from('莫');
const buf2 = Buffer.from('⼩尚');
const bigBuf = at([buf1, buf2]);
console.String()); // 莫⼩尚
关于at的使⽤,稍后也会进⾏详解。
target:被拷贝的Buffer或Uint8Array,也就是我们的⼤容量Buffer。
targetStart:target内开始写⼊的偏移量,默认值为0。
sourceStart:buf内开始复制的偏移量,默认值为0。
sourceEnd:buf内停⽌复制的偏移量(不包括),默认值为buf.length。
[callBack]:复制的字节数。
我们刚才使⽤了py进⾏了简单的扩容操作,那么py的实现原理是什么呢。
⽅法实现
⾸先我们清楚,py中⼀共接受四个参数,分别是target、targetStart、sourceStart、sourceEnd。
现在我们来看⼀下完成后的代码。
py = function (target, targetStart, sourceStart = 0, sourceEnd = this.length) {
for (let i = sourceStart; i < sourceEnd; i++) {
target[targetStart++] = this[i];
}
}
实现了py,我们就可以来看⼀下at⽅法了。
list:要拼接的Buffer或Uint8Array实例的数组列表。
totalLength:连接时list中Buffer实例的总长度。
callBack:返回⼀个新的Buffer。
在上⾯的例⼦中,我们使⽤at实现了⼀个Buffer扩容的例⼦。
下⾯我们就来详解⼀下它的⽅法实现。
⽅法实现
根据at的使⽤⽅式,我们可以⼤概了解到⼀个思路。那就是将传⼊的Buffer实例通过拷贝的⽅式将其拼接成⼀个⼤的Buffer类。这样我们就可以⼤概⼿写出其实现原理了。
let buffer = Buffer.alloc(len);
// 记录下⼀次开始拼接的位置
let offset = 0;
bufferList.forEach(buf => {
// 判断是不是 Buffer
if (Buffer.isBuffer(buf)) {
offset += buf.length;
}
})
return buffer;
}
这样我们就完成了at的实现。
本篇⽂章由莫⼩尚创作,⽂章中如有任何问题和纰漏,欢迎您的指正与交流。
您也可以关注我的、和,我会在⽂章产出后同步上传到这些平台上。
最后感谢您的⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论