面試官:說說對 Node 中的 Buffer 的理解?應(yīng)用場景?
本文轉(zhuǎn)載自微信公眾號「JS每日一題」,作者灰灰。轉(zhuǎn)載本文請聯(lián)系JS每日一題公眾號。
一、是什么
在Node應(yīng)用中,需要處理網(wǎng)絡(luò)協(xié)議、操作數(shù)據(jù)庫、處理圖片、接收上傳文件等,在網(wǎng)絡(luò)流和文件的操作中,要處理大量二進(jìn)制數(shù)據(jù),而Buffer就是在內(nèi)存中開辟一片區(qū)域(初次初始化為8KB),用來存放二進(jìn)制數(shù)據(jù)
在上述操作中都會存在數(shù)據(jù)流動,每個數(shù)據(jù)流動的過程中,都會有一個最小或最大數(shù)據(jù)量
如果數(shù)據(jù)到達(dá)的速度比進(jìn)程消耗的速度快,那么少數(shù)早到達(dá)的數(shù)據(jù)會處于等待區(qū)等候被處理。反之,如果數(shù)據(jù)到達(dá)的速度比進(jìn)程消耗的數(shù)據(jù)慢,那么早先到達(dá)的數(shù)據(jù)需要等待一定量的數(shù)據(jù)到達(dá)之后才能被處理
這里的等待區(qū)就指的緩沖區(qū)(Buffer),它是計(jì)算機(jī)中的一個小物理單位,通常位于計(jì)算機(jī)的 RAM 中
簡單來講,Nodejs不能控制數(shù)據(jù)傳輸?shù)乃俣群偷竭_(dá)時(shí)間,只能決定何時(shí)發(fā)送數(shù)據(jù),如果還沒到發(fā)送時(shí)間,則將數(shù)據(jù)放在Buffer中,即在RAM中,直至將它們發(fā)送完畢
上面講到了Buffer是用來存儲二進(jìn)制數(shù)據(jù),其的形式可以理解成一個數(shù)組,數(shù)組中的每一項(xiàng),都可以保存8位二進(jìn)制:00000000,也就是一個字節(jié)
例如:
- const buffer = Buffer.from("why")
其存儲過程如下圖所示:
二、使用方法
Buffer 類在全局作用域中,無須require導(dǎo)入
創(chuàng)建Buffer的方法有很多種,我們講講下面的兩種常見的形式:
- Buffer.from()
- Buffer.alloc()
Buffer.from()
- const b1 = Buffer.from('10');
- const b2 = Buffer.from('10', 'utf8');
- const b3 = Buffer.from([10]);
- const b4 = Buffer.from(b3);
- console.log(b1, b2, b3, b4); // <Buffer 31 30> <Buffer 31 30> <Buffer 0a> <Buffer 0a>
Buffer.alloc()
- const bAlloc1 = Buffer.alloc(10); // 創(chuàng)建一個大小為 10 個字節(jié)的緩沖區(qū)
- const bAlloc2 = Buffer.alloc(10, 1); // 建一個長度為 10 的 Buffer,其中全部填充了值為 `1` 的字節(jié)
- console.log(bAlloc1); // <Buffer 00 00 00 00 00 00 00 00 00 00>
- console.log(bAlloc2); // <Buffer 01 01 01 01 01 01 01 01 01 01>
在上面創(chuàng)建buffer后,則能夠toString的形式進(jìn)行交互,默認(rèn)情況下采取utf8字符編碼形式,如下
- const buffer = Buffer.from("你好");
- console.log(buffer);
- // <Buffer e4 bd a0 e5 a5 bd>
- const str = buffer.toString();
- console.log(str);
- // 你好
如果編碼與解碼不是相同的格式則會出現(xiàn)亂碼的情況,如下:
- const buffer = Buffer.from("你好","utf-8 ");
- console.log(buffer);
- // <Buffer e4 bd a0 e5 a5 bd>
- const str = buffer.toString("ascii");
- console.log(str);
- // d= e%=
當(dāng)設(shè)定的范圍導(dǎo)致字符串被截?cái)嗟臅r(shí)候,也會存在亂碼情況,如下:
- const buf = Buffer.from('Node.js 技術(shù)棧', 'UTF-8');
- console.log(buf) // <Buffer 4e 6f 64 65 2e 6a 73 20 e6 8a 80 e6 9c af e6 a0 88>
- console.log(buf.length) // 17
- console.log(buf.toString('UTF-8', 0, 9)) // Node.js �
- console.log(buf.toString('UTF-8', 0, 11)) // Node.js 技
所支持的字符集有如下:
- ascii:僅支持 7 位 ASCII 數(shù)據(jù),如果設(shè)置去掉高位的話,這種編碼是非??斓?/li>
- utf8:多字節(jié)編碼的 Unicode 字符,許多網(wǎng)頁和其他文檔格式都使用 UTF-8
- utf16le:2 或 4 個字節(jié),小字節(jié)序編碼的 Unicode 字符,支持代理對(U+10000至 U+10FFFF)
- ucs2,utf16le 的別名
- base64:Base64 編碼
- latin:一種把 Buffer 編碼成一字節(jié)編碼的字符串的方式
- binary:latin1 的別名,
- hex:將每個字節(jié)編碼為兩個十六進(jìn)制字符
三、應(yīng)用場景
Buffer的應(yīng)用場景常常與流的概念聯(lián)系在一起,例如有如下:
- I/O操作
- 加密解密
- zlib.js
I/O操作
通過流的形式,將一個文件的內(nèi)容讀取到另外一個文件
- const fs = require('fs');
- const inputStream = fs.createReadStream('input.txt'); // 創(chuàng)建可讀流
- const outputStream = fs.createWriteStream('output.txt'); // 創(chuàng)建可寫流
- inputStream.pipe(outputStream); // 管道讀寫
加解密
在一些加解密算法中會遇到使用 Buffer,例如 crypto.createCipheriv 的第二個參數(shù) key 為 string 或 Buffer 類型
zlib.js
zlib.js 為 Node.js 的核心庫之一,其利用了緩沖區(qū)(Buffer)的功能來操作二進(jìn)制數(shù)據(jù)流,提供了壓縮或解壓功能
參考文獻(xiàn)
http://nodejs.cn/api/buffer.html
https://segmentfault.com/a/1190000019894714