在nodejs中,我们无法直接发送二进制数据,如图像、视频等媒体文件。而Buffer的出现就是专门用来存储二进制数据的。Buffer是node.js的核心模块,因此它可以直接通过Buffer.from();来将数据存储进被分配的内存中。
Buffer.from(str);我们写入的虽然是字符串,但当我们打印后得到的确实16进制数据,也因为如此,一个Buffer所对应的取值范围为00-FF,即0-255之间,而对应的二进制则是:00000000-11111111(一位代表四位二进制数)。 在这里我们可以了解一下数据存储规则:
一位二进制=1bit 8bit=1byte(一字节) 1kb=1024byte在这里,因为字母汉字在所占内存容量也有所不同,如下:
var str="Hello 李" var buf=Buffer.from(str,"UTF-8"); console.log(str.length); // 7 console.log(buf.length); // 9我们可以看到,这里一个字是占3个字节的。
1.可以通过 Buffer.alloc(size);来创建一个固定长度的Buffer类,且空间是连续的; Nodejs并不会去操作内存,它把这一工作交给C++完成内存分配申请,再通过JavaScript进行管理。
var buf=Buffer.alloc(5); //分配长度为5的连续内存空间,他的初始值为0我们也可以为创建的内存空间赋值:
buf[0]=39; //39 buf[1]=-100; //156 buf[2]=257; //256 buf[3]=0xaa //170 buf[5]=1 //打印buf时,值不会变化值得注意的是Buffer一旦创建,它的值就不会改变。想在创建时分配器初始值,则可写为: Buffer.alloc(10, 1); 它每一项的初始值都会为01
2.通过Buffer.allocUnsafe(10);来创建固定长度Buffer,通过allocUnsafe创建的内存空间将不会初始化数据,返回的 Buffer 实例可能包含旧数据。
如果Buffer分配空间不足,则只会写入一部分:
buf = Buffer.alloc(10); len = buf.write("www.bilibili.com"); console.log("字节数 : "+ len); //字节数10实例:
buf = Buffer.alloc(26); for (var i = 0 ; i < 26 ; i++) { buf[i] = i + 97; } console.log( buf.toString('ascii')); // 输出: abcdefghijklmnopqrstuvwxyz console.log( buf.toString('ascii',0,5)); // 输出: abcde console.log( buf.toString('utf8',0,5)); // 输出: abcde console.log( buf.toString(undefined,0,5)); // 使用 'utf8' 编码, 并输出: abcde通过 Buffer.concat(list[, totalLength]);合并缓冲区:
var buffer1 = Buffer.from(('张三')); var buffer2 = Buffer.from(('李四')); var buffer3 = Buffer.concat([buffer1,buffer2]); console.log("buffer3: " + buffer3.toString()); //buffer3:张三李四buf.compare(otherBuffer);可以对缓冲区进行比较:
var buffer1 = Buffer.from('ABC'); var buffer2 = Buffer.from('ABCD'); var result = buffer1.compare(buffer2); if(result < 0) { console.log(buffer1 + " 在 " + buffer2 + "之前"); //ABC在ABCD之前 }else if(result == 0){ console.log(buffer1 + " 与 " + buffer2 + "相同"); }else { console.log(buffer1 + " 在 " + buffer2 + "之后"); }如下实例:
var buf1 = Buffer.from('abcdefgh'); var buf2 = Buffer.from('ABC'); buf2.copy(buf1, 2,0); console.log(buf1.toString()); //abABCfghbuf.length;即可获得缓冲区长度
var buffer = Buffer.from('www.runoob.com'); // 缓冲区长度 console.log("buffer length: " + buffer.length); //buffer length: 14之前js只能处理字符串数据类型,且对字符串的操作都是得到一个新的字符串,不会对源字符串做出改变,而buffer会通过buffer[index]的方式对固定位置的字节进行更改。Buffer是一个典型的Javascript和C++结合的模块,性能相关部分用C++实现,非性能相关部分用javascript实现。Node在进程启动时Buffer就已经加装进入内存,并将其放入全局对象,因此无需require。 Buffer对象的内存分配不是在V8的堆内存中,在Node的C++层面实现内存的申请。 Nodejs采用slab分配机制,slab是一种动态内存管理机制,slab有三种状态:
full:完全分配状态 partial:部分分配状态 empty:没有被分配状态nodejs会根据分配内存大小对Buffer对象进行分类,申请内存小于4kb时,就会存入初始化的slab单元中。当继续申请小于4kb且当前第一个初始化的8k空间足够的情况下会继续存入第一个初始化的8kkong空间池(如果被初始化的8k池的空间剩余2k,这个时候再去申请一个大于2k并且小于4k的内存空间,就会去新申请一个slab单元空间,上次初始化的slab单元的剩余2k内存就会被浪费掉,无法再使用)。 Buffer的分配过程中主要使用一个局部变量pool作为中间处理对象,处于分配状态的slab单元都指向它。
var pool; function allocPool() { pool = new SlowBuffer(Buffer.poolSize); pool.used = 0; }如果pool没有被创建,将会创建一个新的slab单元指向它:
if (!pool || pool.length - pool.used < this.length) allocPool();同时当前Buffer对象的parent属性指向该slab,并记录下是从这个slab的哪个位置(offset)开始使用的,slab对象自身也记录被使用了多少字节:
this.parent = pool; this.offset = pool.used; pool.used += this.length; if (pool.used & 7) pool.used = (pool.used + 8) & ~7;这时候的slab状态为partial。当再次创建一个Buffer对象时,构造过程中将会判断这个slab的剩余空间是否足够。如果足够,使用剩余空间。如果slab剩余的空间不够,将会构造新的slab,原slab中剩余的空间会造成浪费。