国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

淺談Node.js:Buffer模塊

2019-11-19 18:39:48
字體:
來源:轉載
供稿:網友

Javascript在客戶端對于unicode編碼的數據操作支持非常友好,但是對二進制數據的處理就不盡人意。Node.js為了能夠處理二進制數據或非unicode編碼的數據,便設計了Buffer類,該類實現了Uint8Array接口,并對其進行了優化,它的實例類似于整型數組,但是它的大小在創建后便不可調整。在介紹Buffer如何使用之前,先介紹幾個知識點。

1、V8引擎的內存使用限制

V8引擎最大堆內存使用在32位系統上默認為512M,在64位系統上是1GB,雖然可以使用--max-old-space-size參數調整該值,但還是建議要用到大內存的時候使用Buffer或Stream,因為Buffer的內存分配不在V8的堆上。

2、單個Buffer實例大小限制

單個Buffer實例的大小最大數值為1GB-1(32位系統)或2GB-1(64位系統),所以在創建Buffer實例的時候不能超過該值,或者使用readFile()方法讀取大文件,否則將拋出RangeError錯誤。

3、8KB池

Nodejs在創建Buffer實例的時候,當用戶申請的空間大于8KB,會直接調用內部的createUnsafeBuffer()方法創建一個Buffer,如果申請的空間大于0且小于4KB,新的Buffer則會建立在當前的8kb SLAB上,并更新剩余空間,如下圖所示:

下面介紹Buffer API的簡單使用:

1、創建Buffer實例

 使用Buffer.from(), Buffer.alloc(), Buffer.allocUnsafe()等方法來創建一個Buffer實例,6.0版本以前直接使用構造函數創建的方法new Buffer()已被丟棄,不推薦使用,因為有可能會造成內存泄漏。
 方法Buffer.alloc(size[, fill[, encoding]]),參數含義如下:

  • size,指定buffer的長度,但不能超過buffer.kMaxLength,若不是數字則報錯
  • fill,指定初始化buffer的值,默認為0
  • encoding,如果fill是字符串,則該參數指定fill的編碼

使用如下所示:

const buf1 = Buffer.alloc(10);console.log(buf1);//<Buffer 00 00 00 00 00 00 00 00 00 00>const buf2 = Buffer.alloc(10,'hello');console.log(buf2);//<Buffer 68 65 6c 6c 6f 68 65 6c 6c 6f>const buf3 = Buffer.alloc(10,'hello','base64');console.log(buf3);//<Buffer 85 e9 65 85 e9 65 85 e9 65 85>

方法Buffer.allocUnsafe(size),size參數指定buffer的大小,該方法返回一個沒有初始化的buffer,因此可能還保留有敏感的數據,造成信息的泄漏,建議使用buffer.fill(0)函數初始化buffer,該方法與Buffer.alloc(size, fill)是不一樣的,有可能使用8KB池。使用如下所示:

const buf4 = Buffer.allocUnsafe(10);console.log(buf4);//<Buffer 68 fb 4d 00 00 00 00 00 08 00>,可以看出是有數據的buf4.fill(0);console.log(buf4);//<Buffer 00 00 00 00 00 00 00 00 00 00>

方法Buffer.allocUnsafeSlow(size),參數含義同上,該方法不會使用Buffer池,容易造成內存的浪費,使用如下所示:

const buf5 = Buffer.allocUnsafeSlow(10);console.log(buf5);//<Buffer 38 00 24 00 00 00 00 00 00 00>

方法Buffer.from(value,[...]),這里分為四種情況,如下所示:

第一,value為16進制數組,將數組轉化為buffer,如果不是16進制,則會進行轉換,如下:

const buf6 = Buffer.from([1,2,3,5,17]);console.log(buf6);//<Buffer 01 02 03 05 11>

第二,value為字符串,則轉換字符串為buffer,該方法會使用buffer池,如下:

const buf7 = Buffer.from('hello world!');console.log(buf7);//<Buffer 01 02 03 05 11>

第三,value為buffer實例,則將value拷貝至新的buffer中,這里只是值的拷貝,不會共享內存,如下:

const buf8 = Buffer.from('hello world');const buf9 = Buffer.from(buf8);console.log(buf8);//<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>console.log(buf9);//<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>buf9[0] = 0x66;console.log(buf8);//<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>console.log(buf9);//<Buffer 66 65 6c 6c 6f 20 77 6f 72 6c 64>

第四,value為arrayBuffer時,還有兩個可選參數[, byteOffset[, length]],byteOffset指定從arrayBuffer開始復制的位置,length復制的長度。如下:

const arr = new Uint8Array(2);arr[0] = 128;arr[1] = 200;const buf10 = Buffer.from(arr,0,2);console.log(buf10);//<Buffer 80 c8>

如果引用的是arr.buffer,則新創建的buffer buf10與arr共享內存,如下:

const arr = new Uint8Array(2);arr[0] = 128;arr[1] = 200;const buf10 = Buffer.from(arr.buffer);arr[0] = 254;console.log(buf10);//<Buffer fe c8>

2、buffer解碼

使用buf.toString([encoding[, start[, end]]])方法將buffer轉換成字符串,encoding指定字符編碼,默認為'utf8',start開始位置,end結束位置(不包括),目前encoding只支持'ascii,utf8,utf16le,ucs2,base64,latin1,binary,hex',使用如下所示:

const buf12 = Buffer.from('我愛中國');console.log(buf12.toString('base64'));//5oiR54ix5Lit5Zu9console.log(buf12.toString('utf8'));//我愛中國console.log(buf12.toString('hex'));//e68891e788b1e4b8ade59bbd

3、buffer拼接、復制、填充、分割

方法buf.fill(value[, offset[, end]][, encoding])使用指定的值填充buffer,參數offset指定填充的起始位置,end為結束位置,使用如下所示:

console.log(Buffer.allocUnsafe(5).fill('a').toString());//aaaaaconsole.log(Buffer.allocUnsafe(5).fill(65).toString('utf8'));//AAAAA

方法Buffer.concat(list[, totalLength])將多個buffer合并在一起,并返回一個新的buffer實例,參數totalLength為指定的buffers的長度總和,如果不提供該值,函數內部會循環去獲取每一個buffer的長度,然后進行拼接,因此為了速度,最好指定一個總長度,使用如下:

function bufferInjoin(buffArr){  var len = 0;  buffArr.forEach((buff,idx,arr)=>{    len+=buff.length;  });  var buffer = Buffer.concat(buffArr,len);  return buffer;}var buff = bufferInjoin([Buffer.from('hehe'),Buffer.allocUnsafe(5).fill('a')]);console.log(buff);//<Buffer 68 65 68 65 61 61 61 61 61>console.log(buff.length);//9console.log(buff.toString());//heheaaaaa

方法buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])可以實現buf到target的復制,參數含義如下:

  • target,復制目標
  • targetStart,復制目標開始被覆蓋的位置
  • sourceStart,復制源開始復制的位置
  • sourceEnd,復制源復制結束的位置

使用如下所示:

const buf1 = Buffer.from('hello world!');const buf2 = Buffer.allocUnsafe(5).fill('x');buf1.copy(buf2,0,0,5);console.log(buf2.toString());//hello

方法buf.slice([start[, end]])可以分割buffer,返回一個新的buffer,但是仍然是引用原buffer,因此改變原buffer數據,該新buffer也會跟著改變,如果參數start,end為負數,則先要加上buffer的長度再進行計算,如下所示:

const buf1 = Buffer.from('hello world.');const buf2 = buf1.slice(0);console.log(buf2);//<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64 2e>buf2[0] = 88;console.log(buf1);//<Buffer 58 65 6c 6c 6f 20 77 6f 72 6c 64 2e>const buf3 = buf1.slice(-6,-1);console.log(buf3.toString());//world

3、buffer讀寫

buffer寫操作通過write開頭的寫api來完成,主要有以下這些:

  • buf.write(string[, offset[, length]][, encoding]),向buffer寫入字符串
  • buf.writeDoubleBE(value, offset[, noAssert])寫入64位浮點型數字,大端對齊
  • buf.writeDoubleLE(value, offset[, noAssert]),寫入64位浮點型數字,小端對齊
  • buf.writeFloatBE(value, offset[, noAssert]),寫入32位浮點型數字,大端對齊
  • buf.writeFloatLE(value, offset[, noAssert]),寫入32位浮點型數字,小端對齊
  • buf.writeInt8(value, offset[, noAssert]),寫入有符號8位整型數字
  • buf.writeInt16BE(value, offset[, noAssert]),寫入有符號16位整型數字,大端對齊
  • buf.writeInt16LE(value, offset[, noAssert]),寫入有符號16位整型數字,小端對齊
  • buf.writeInt32BE(value, offset[, noAssert]),寫入有符號32位整型數字,大端對齊
  • buf.writeInt32LE(value, offset[, noAssert]),寫入有符號32位整型數字,小端對齊
  • buf.writeIntBE(value, offset, byteLength[, noAssert]),以下便不再累述
  • buf.writeIntLE(value, offset, byteLength[, noAssert])
  • buf.writeUInt8(value, offset[, noAssert])
  • buf.writeUInt16BE(value, offset[, noAssert])
  • buf.writeUInt16LE(value, offset[, noAssert])
  • buf.writeUInt32BE(value, offset[, noAssert])
  • buf.writeUInt32LE(value, offset[, noAssert])
  • buf.writeUIntBE(value, offset, byteLength[, noAssert])
  • buf.writeUIntLE(value, offset, byteLength[, noAssert])

buffer讀操作由read開頭的api完成,主要有以下這些:

  • buf.readDoubleBE(offset[, noAssert])
  • buf.readDoubleLE(offset[, noAssert])
  • buf.readFloatBE(offset[, noAssert])
  • buf.readFloatLE(offset[, noAssert])
  • buf.readInt8(offset[, noAssert])
  • buf.readInt16BE(offset[, noAssert])
  • buf.readInt16LE(offset[, noAssert])
  • buf.readInt32BE(offset[, noAssert])
  • buf.readInt32LE(offset[, noAssert])
  • buf.readIntBE(offset, byteLength[, noAssert])
  • buf.readIntLE(offset, byteLength[, noAssert])
  • buf.readUInt8(offset[, noAssert])
  • buf.readUInt16BE(offset[, noAssert])
  • buf.readUInt16LE(offset[, noAssert])
  • buf.readUInt32BE(offset[, noAssert])
  • buf.readUInt32LE(offset[, noAssert])
  • buf.readUIntBE(offset, byteLength[, noAssert])
  • buf.readUIntLE(offset, byteLength[, noAssert])

使用如下所示,以32無符號整型為例:

const buf = Buffer.allocUnsafe(8);buf.writeUInt32BE(0x12345678,0)console.log(buf);const data = buf.readUInt32BE(0);console.log(data.toString(16));

最后利用buffer讀API完成一個獲取PNG格式圖片尺寸的小工具,在開始編碼之前,先簡單介紹下PNG文件組成,如下所示:

PNG文件標志 PNG數據塊 …… PNG數據塊

這里我們只要用到PNG文件標識和PNG數據塊的第一個塊IHDR文件頭數據塊。文件標識是固定的8個字節,為89 50 4E 47 0D 0A 1A 0A,IHDR數據塊的長度為13個字節,格式如下:

域的名稱 字節數 說明
Width 4 bytes 寬度
Height 4 bytes 高度
Bit depth 1 bytes 圖像深度
ColorType 1 bytes 顏色類型
Compression method 1 bytes 壓縮方法
Filter method 1 bytes 濾波器方法
Interlace method 1 bytes 隔行掃描方法

開始編碼,如下所示:

const fs = require('fs');const path = require('path');const argvs = process.argv.slice(2);if(argvs.length<=0){  console.error('請輸入圖片:png.js img1 img2 ...');  process.exit(-1);}argvs.forEach((img,idx,arr)=>{  var stat = fs.statSync(img);  fs.open(img,'r',(err,fd)=>{    if(err) throw err;    var buff = Buffer.alloc(stat.size);    fs.read(fd,buff,0,stat.size,0,(err, bytesRead, buffer)=>{      if(err) throw err;      fs.close(fd,()=>{});      getImgDimension(buff,(err,dimension)=>{        if(err) throw err;        console.log(`${img}的尺寸為:${dimension.width}x${dimension.height}`);      });    });  });});function getImgDimension(buff,cb){  if((buff.toString('utf8',1,8) === 'PNG/r/n/x1a/n') && (buff.toString('utf8',12,16) === 'IHDR')){    return cb(null,{      width:buff.readUInt32BE(16),      height:buff.readUInt32BE(20)    }),!0;  }else{    return cb(new Error('不是PNG圖片'),{}),!1;  }}

執行結果如下:

E:/developmentdocument/nodejsdemo>node png.js 20160824083157.png 下載.png
 20160824083157.png的尺寸為:195x195
下載.png的尺寸為:720x600

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 上饶县| 临武县| 响水县| 佳木斯市| 南昌县| 淄博市| 金山区| 江山市| 介休市| 儋州市| 香港 | 定襄县| 常宁市| 买车| 辉县市| 唐河县| 青州市| 长海县| 太和县| 巴东县| 浦县| 黄石市| 铜川市| 从江县| 巫溪县| 宣城市| 离岛区| 玉林市| 永寿县| 常州市| 新野县| 牟定县| 台州市| 芦溪县| 亳州市| 峨边| 临武县| 历史| 新宁县| 磐石市| 五台县|