Buffer(緩衝器)

什麼是Buffer

  • 緩衝區Buffer是暫時存放輸入輸出數據的一段內存。
  • JS語言沒有二進制數據類型,而在處理TCP和文件流的時候,必需要處理二進制數據。
  • NodeJS提供了一個Buffer對象來提供對二進制數據的操做
  • 是一個表示固定內存分配的全局對象,也就是說要放到緩存區中的字節數須要提早肯定
  • Buffer比如由一個8位字節元素組成的數組,能夠有效的在JavasScript中表示二進制數據 Buffer 類被引入做爲 Node.js API 的一部分,使其能夠在 TCP 流或文件系統操做等場景中處理二進制數據流。

Buffer 類的實例相似於整數數組,但 Buffer 的大小是固定的、且在 V8 堆外分配物理內存。 Buffer 的大小在被建立時肯定,且沒法調整。javascript

Buffer 類在 Node.js 中是一個全局變量,所以無需使用 require('buffer').Buffer。前端

怎麼建立buffer? 第一種方式:Buffer.alloc()java

let buffer = Buffer.alloc(6);
 //建立一個長度爲6,而且用0填充的Buffer。
 //這樣申請方式,內存永遠是乾淨的。
 // 這種聲明也比較耗時,由於聲明以後,還要把裏面的東西手動清空
 //輸出:<Buffer 00 00 00 00 00 00>
 
 let buffer2 = Buffer.alloc(6,1);
 // 建立一個長度爲 六、且用 0x1 填充的 Buffer。 
 //輸出:<Buffer 01 01 01 01 01 01>
複製代碼

第二種方式:Buffer.allocUnsafe()編程

let buffer = Buffer.allocUnsafe(6);
// 建立一個長度爲 六、且未初始化的 Buffer。
// 這個方法比調用 Buffer.alloc() 更快
//輸出:<Buffer 07 00 00 00 00 00>
//但裏面的東西是不安全的,可能含有舊數據。
//所以須要使用 fill() 或 write() 重寫
buffer.fill(0);//對buffer進行重寫
//輸出:<Buffer 00 00 00 00 00 00>
複製代碼

定義buffer的3種方式

  1. 經過長度定義
// 建立一個長度爲 十、且用 0 填充的 Buffer。
let buf1 = Buffer.alloc(10);
// 建立一個長度爲 十、且用 0x1 填充的 Buffer。
let buf2 = Buffer.alloc(10, 1);
// 建立一個長度爲 十、且未初始化的 Buffer。
let buf3 = Buffer.allocUnsafe(10);
複製代碼
  1. 經過字符串定義
let buf = Buffer.from('hello world');
//輸出:<Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
//默認是轉成utf8格式的數據,也能夠轉成其餘格式的數據,不支持gbk

複製代碼

3 經過數組定義數組

let buf = Buffer.from([1, 2, 3]);
// 建立一個包含 [0x1, 0x2, 0x3] 的 Buffer。
//<Buffer 01 02 03>
let buf2 = Buffer.from([16, 17, 18]);
//<Buffer 10 11 12>
//Buffer存的都是16進制,可是form存放的都是10進制,因此要除以16
複製代碼

以上3種方法,是建立buffer的3種方式緩存


buf.write(string[, offset[, length]][, encoding])安全

  • string 要寫入 buf 的字符串。
  • offset 開始寫入 string 前要跳過的字節數。默認: 0。
  • length 要寫入的字節數。默認: buf.length - offset。
  • encoding string 的字符編碼。默認: 'utf8'。
  • 返回: 寫入的字節數。

操做內存空間

好比有個字符串'我愛編程',但願將我和愛編程分開輸出,也就是第一次將我放到一個變量裏,把剩餘3個字放到一個變量裏。 具體操做:ui

// 先申請一個Buffer
// 一個漢字3個字節,4個漢字12個字節
let buffer = Buffer.alloc(12);//裏面是0填充的,內存是乾淨的
// 再構建兩個buf1和buf2,而後把他們寫到第一個個buffer裏
let buf1 = '我';
let buf2 = '愛編程';
// write的參數分別是:寫入的內容 ,偏移量,長度,編碼格式
buffer.write(buf1,0,3,'utf8');//往buffer裏面寫內容buf1,從當前buffer的開頭寫,因此是第0個,長度是3,由於一個漢字3個字節
// 再寫一個buf2
buffer.write(buf2,3,9,'utf8');
console.log(buffer);
//<Buffer e6 88 91 e7 88 b1 e7 bc 96 e7 a8 8b>
// 把buffer和字符串進行轉換
console.log(buffer.toString());
//我愛編程
複製代碼

進制

  • 0b 2進制
  • 0x 16進制
  • 0o 8進制
parseInt():任意進制字符串轉換爲十進制
parseInt("11", 2); // 3 2進制轉10進制
parseInt("77", 8); // 63 8進制轉10進制
parseInt("e7", 16); //175 16進制轉10進制
複製代碼
toString():10進制轉換爲其它進制字符串
(3).toString(2)) // "11" 十進制轉2進制
(17).toString(16) // "11" 十進制轉16進制
(33).toString(32) // "11" 十提製轉32進制
複製代碼

buffer其餘經常使用的方法

buf.slice([start[, end]]);this

  • start : 新建的 Buffer 開始的位置。 默認: 0
  • end : 新建的 Buffer 結束的位置(不包含)。 默認: buf.length
  • 返回 : <Buffer>
let buffer = Buffer.alloc(6);
let newBuffer = buffer.slice(0,3);
newBuffer[0] = 100;
console.log(buffer)
//<Buffer 64 00 00 00 00 00>
//因而可知,buffer裏面存的是內存地址
複製代碼

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

  • target <Buffer> | <Uint8Array> 要拷貝進的 Buffer 或 Uint8Array。
  • targetStart target 中開始拷貝進的偏移量。 默認: 0
  • sourceStart buf 中開始拷貝的偏移量。 當 targetStart 爲 undefined 時忽略。 默認: 0
  • sourceEnd buf 中結束拷貝的偏移量(不包含)。 當 sourceStartundefined 時忽略。 默認: buf.length
  • 返回: <integer> 被拷貝的字節數。

拷貝 buf 的一個區域的數據到 target 的一個區域,即使 target 的內存區域與 buf 的重疊。編碼

let buffer = Buffer.alloc(6);
let buf1 = Buffer.from('一');
let buf2 = Buffer.from('萬');
//要打印出萬一
// 要把buf2 buf1的內容拷貝到buffer中
// write和copy的區別:write拷的是字符串,copy拷的是buffer
// 參數:目標 target中開始拷貝進的偏移量 buf1中開始拷貝的偏移量 buf1中結束拷貝的偏移量(不包含)
buf1.copy(buffer,3,0,3);//由於一時第二個文字,因此寫在第3位(一個文字3個字節,第一個文字被佔用,即012被佔用)
buf2.copy(buffer,0,0,3);
console.log(buffer.toString())
//輸出:萬一
複製代碼

那麼問題來了,如何實現copy方法? 首先,copy是Buffer實例上的方法,因此應該定義在Buffer原型上。

Buffer.prototype.mycopy = function(target, targetStart, sourceStart, sourceEnd){
    /** * 有4個參數 * 目標 * target中開始拷貝進的偏移量 * buf1中開始拷貝的偏移量 * buf1中結束拷貝的偏移量(不包含) * */
    //Buffer跟數組很像,有個迭代的功能
    for(let i = sourceStart;i<sourceEnd; i++){//迭代每一項
        // 從偏移量開始寫 
        target[i+targetStart] = this[i];    //迭代每一項賦給目標buffer,this是buf1實例
    } 

}
buf1.mycopy(buffer,3,0,3);//由於一時第二個文字,因此寫在第3位(一個文字3個字節,第一個文字被佔用,即012被佔用)
buf2.mycopy(buffer,0,0,3);
console.log(buffer.toString())
複製代碼

Buffer.concat(list[, totalLength])

  • list < Array > 要合併的 Buffer 或 Uint8Array 實例的數組
  • totalLength < integer > 合併時 listBuffer 實例的總長度
  • 返回: < Buffer >

返回一個合併了 list 中全部 Buffer 實例的新建的 Buffer 。 若是 list 中沒有元素、或 totalLength 爲 0 ,則返回一個新建的長度爲 0 的 Buffer 。 若是沒有提供 totalLength ,則從 list 中的 Buffer 實例計算獲得。 爲了計算 totalLength 會致使須要執行額外的循環,因此提供明確的長度會運行更快。 若是提供了 totalLength,totalLength 必須是一個正整數。若是從 list 中計算獲得的 Buffer 長度超過了 totalLength,則合併的結果將會被截斷爲 totalLength 的長度。

let buffer1 = Buffer.from('前');
let buffer2 = Buffer.from('端');
let buffer = Buffer.concat([buffer1,buffer2]).toString();//返回的是新Buffer,要toString()轉譯一下
console.log(buffer);
//輸出:前端

let buf = Buffer.concat([buffer1,buffer2],10).toString();
console.log(buf);
//若是把長度寫多了,會有問題,見下圖
//多寫的內容就是0
複製代碼

此處輸入圖片的描述

split

buf.indexOf(value[, byteOffset][, encoding])

  • value < string > | < Buffer > | < Uint8Array > | < integer > 要搜索的值
  • byteOffset < integer > buf 中開始搜索的位置。默認: 0
  • encoding < string > 若是 value 是一個字符串,則這是它的字符編碼。 默認: 'utf8'
  • 返回: < integer > buf 中 value 首次出現的索引,若是 buf 沒包含 value 則返回 -1

若是 value 是:

  • 字符串,則 value 根據 encoding 的字符編碼進行解析。
  • BufferUint8Array,則 value 會被做爲一個總體使用。若是要比較部分 Buffer,可以使用 buf.slice()。
  • 數值, 則 value 會解析爲一個 0 至 255 之間的無符號八位整數值。
const buf = Buffer.from('this is a buffer');

// 輸出: 0
console.log(buf.indexOf('this'));

// 輸出: 2
console.log(buf.indexOf('is'));

// 輸出: 8
console.log(buf.indexOf(Buffer.from('a buffer')));

// 輸出: 8
// (97 是 'a' 的十進制 ASCII 值)
console.log(buf.indexOf(97));

// 輸出: -1
console.log(buf.indexOf(Buffer.from('a buffer example')));

// 輸出: 8
console.log(buf.indexOf(Buffer.from('a buffer example').slice(0, 8)));


const utf16Buffer = Buffer.from('\u039a\u0391\u03a3\u03a3\u0395', 'ucs2');

// 輸出: 4
console.log(utf16Buffer.indexOf('\u03a3', 0, 'ucs2'));

// 輸出: 6
console.log(utf16Buffer.indexOf('\u03a3', -4, 'ucs2'));
複製代碼
相關文章
相關標籤/搜索