<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入理解 Node.js Buffer 的 encoding

          共 11823字,需瀏覽 24分鐘

           ·

          2021-08-31 09:38

          計算機最小的單位是一個位,也就是 0 和 1,在硬件上通過高低電平來對應。但是只有一位表示的信息太少了,所以又規(guī)定了 8 個位為一個字節(jié),之后數(shù)字、字符串等各種信息都是基于字節(jié)來存儲的。

          字符怎么存儲呢?就是靠編碼,不同的字符對應不同的編碼,然后在需要渲染的時候根據(jù)對應編碼去查字體庫,然后渲染對應字符的圖形。

          字符集

          字符集(charset)最早是 ASCII 碼,也就是 abc ABC 123 等 128 個字符,因為計算機最早就是美國發(fā)明的。后來歐洲也制定了一套字符集標準,叫做 ISO,后來中國也搞了一套,叫做 GBK。

          國際標準化組織覺得不能這樣各自搞一套,不然同一個編碼在不同字符集里面就不同的意思,于是就提出了 unicode 編碼,把全世界大部分編碼收錄,這樣每個字符只有唯一的編碼。

          但是 ASCII 碼只需要 1 個字節(jié)就可以存儲,而 GBK 需要 2 個字節(jié),還有的字符集需要 3 個字節(jié)等。有的只要一個字節(jié)存儲卻存了 2 個字節(jié),比較浪費空間。所以就出現(xiàn)了 utf-8、utf-16、utf-24 等不同編碼方案。

          utf-8、utf-16、utf-24 都是 unicode 編碼,但是具體實現(xiàn)方案不同。

          UTF-8 為了節(jié)省空間,設計了從 1 到 6 個字節(jié)的變長存儲方案。而 UTF-16 是固定 2 個字節(jié),UTF-24 是固定 4 個字節(jié)。

          最后,UTF-8 因為占用空間最少,所以被廣泛應用。

          Node.js 的 Buffer 的 encoding

          每種語言都支持字符集的編碼解碼,Node.js 也同樣。

          Node.js 里面可以通過 Buffer 來存儲二進制的數(shù)據(jù),而二進制的數(shù)據(jù)轉(zhuǎn)為字符串的時候就需要指定字符集,Buffer 的 from、byteLength、lastIndexOf 等方法都支持指定 encoding:

          具體支持的 encoding 有這些:

          utf8、ucs2、utf16le、latin1、ascii、base64、hex

          可能有的同學會發(fā)現(xiàn):base64、hex 不是字符集啊,怎么也出現(xiàn)在這里?

          是的,字節(jié)到字符的編碼方案除了字符集之外,也有用于轉(zhuǎn)為明文字符的 base64、以及轉(zhuǎn)為 16 進制的 hex。

          這也是為什么 Node.js 把它叫做 encoding 而不是 charset,因為支持的編解碼方案不只是字符集。

          如果不指定 encoding,默認是 utf8。

          const buf = Buffer.alloc(11'aGVsbG8gd29ybGQ=''base64');

          console.log(buf.toString());// hello world

          encoding 的 源碼

          我去翻了下 Node.js 關于 encoding 的源碼:

          這一段是實現(xiàn) encoding 的:

          https://github.com/nodejs/node/blob/master/lib/buffer.js#L587-L726

          可以看到每個 encoding 都實現(xiàn)了 encoding、encodingVal、byteLength、write、slice、indexOf 這幾個 api,因為這些 api 用不同 encoding 方案,會有不同的結(jié)果,Node.js 會根據(jù)傳入的 encoding 來返回不同的對象,這是一種多態(tài)的思想。

          const encodingOps = {
            utf8: {
              encoding'utf8',
              encodingVal: encodingsMap.utf8,
              byteLength: byteLengthUtf8,
              write(buf, string, offset, len) => buf.utf8Write(string, offset, len),
              slice(buf, start, end) => buf.utf8Slice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir)
            },
            ucs2: {
              encoding'ucs2',
              encodingVal: encodingsMap.utf16le,
              byteLength(string) => string.length * 2,
              write(buf, string, offset, len) => buf.ucs2Write(string, offset, len),
              slice(buf, start, end) => buf.ucs2Slice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)
            },
            utf16le: {
              encoding'utf16le',
              encodingVal: encodingsMap.utf16le,
              byteLength(string) => string.length * 2,
              write(buf, string, offset, len) => buf.ucs2Write(string, offset, len),
              slice(buf, start, end) => buf.ucs2Slice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)
            },
            latin1: {
              encoding'latin1',
              encodingVal: encodingsMap.latin1,
              byteLength(string) => string.length,
              write(buf, string, offset, len) => buf.latin1Write(string, offset, len),
              slice(buf, start, end) => buf.latin1Slice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir)
            },
            ascii: {
              encoding'ascii',
              encodingVal: encodingsMap.ascii,
              byteLength(string) => string.length,
              write(buf, string, offset, len) => buf.asciiWrite(string, offset, len),
              slice(buf, start, end) => buf.asciiSlice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfBuffer(buf,
                              fromStringFast(val, encodingOps.ascii),
                              byteOffset,
                              encodingsMap.ascii,
                              dir)
            },
            base64: {
              encoding'base64',
              encodingVal: encodingsMap.base64,
              byteLength(string) => base64ByteLength(string, string.length),
              write(buf, string, offset, len) => buf.base64Write(string, offset, len),
              slice(buf, start, end) => buf.base64Slice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfBuffer(buf,
                              fromStringFast(val, encodingOps.base64),
                              byteOffset,
                              encodingsMap.base64,
                              dir)
            },
            hex: {
              encoding'hex',
              encodingVal: encodingsMap.hex,
              byteLength(string) => string.length >>> 1,
              write(buf, string, offset, len) => buf.hexWrite(string, offset, len),
              slice(buf, start, end) => buf.hexSlice(start, end),
              indexOf(buf, val, byteOffset, dir) =>
                indexOfBuffer(buf,
                              fromStringFast(val, encodingOps.hex),
                              byteOffset,
                              encodingsMap.hex,
                              dir)
            }
          };
          function getEncodingOps(encoding{
            encoding += '';
            switch (encoding.length) {
              case 4:
                if (encoding === 'utf8'return encodingOps.utf8;
                if (encoding === 'ucs2'return encodingOps.ucs2;
                encoding = StringPrototypeToLowerCase(encoding);
                if (encoding === 'utf8'return encodingOps.utf8;
                if (encoding === 'ucs2'return encodingOps.ucs2;
                break;
              case 5:
                if (encoding === 'utf-8'return encodingOps.utf8;
                if (encoding === 'ascii'return encodingOps.ascii;
                if (encoding === 'ucs-2'return encodingOps.ucs2;
                encoding = StringPrototypeToLowerCase(encoding);
                if (encoding === 'utf-8'return encodingOps.utf8;
                if (encoding === 'ascii'return encodingOps.ascii;
                if (encoding === 'ucs-2'return encodingOps.ucs2;
                break;
              case 7:
                if (encoding === 'utf16le' ||
                    StringPrototypeToLowerCase(encoding) === 'utf16le')
                  return encodingOps.utf16le;
                break;
              case 8:
                if (encoding === 'utf-16le' ||
                    StringPrototypeToLowerCase(encoding) === 'utf-16le')
                  return encodingOps.utf16le;
                break;
              case 6:
                if (encoding === 'latin1' || encoding === 'binary')
                  return encodingOps.latin1;
                if (encoding === 'base64'return encodingOps.base64;
                encoding = StringPrototypeToLowerCase(encoding);
                if (encoding === 'latin1' || encoding === 'binary')
                  return encodingOps.latin1;
                if (encoding === 'base64'return encodingOps.base64;
                break;
              case 3:
                if (encoding === 'hex' || StringPrototypeToLowerCase(encoding) === 'hex')
                  return encodingOps.hex;
                break;
            }
          }

          總結(jié)

          計算機中存儲數(shù)據(jù)的最小單位是位,但是存儲信息最小的單位是字節(jié),基于編碼和字符的映射關系又實現(xiàn)了各種字符集,包括 ascii、iso、gbk 等,而國際標準化組織提出了 unicode 來包含所有字符,unicode 實現(xiàn)方案有若干種:utf-8、utf-16、utf-32,他們分別用不同的字節(jié)數(shù)來存儲字符。其中 utf-8 是變長的,存儲體積最小,所以被廣泛應用。

          Node.js 通過 Buffer 存儲二進制數(shù)據(jù),而轉(zhuǎn)為字符串時需要指定編碼方案,這個編碼方案不只是包含字符集(charset),也支持 hex、base64 的方案,包括:

          utf8、ucs2、utf16le、latin1、ascii、base64、hex

          我們看了下 encoding 的 Node.js 源碼,發(fā)現(xiàn)每種編碼方案都會用實現(xiàn)一系列 api,這是一種多態(tài)的思想。

          encoding 是學習 Node.js 頻繁遇到的一個概念,而且 Node.js 的 encoding 不只是包含 charset,希望這篇文章能夠幫大家了解編碼和字符集。


          瀏覽 18
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕 国产精品 | 青青激情视频 | 菠萝 成人网站视频 | 18禁网站网址 | 豆花视频每日更新 |