WebSocket系列之字符串如何與二進制數據間進行互相轉換

概述

上一篇博客我們說到了如何進行數字類型(如Short、Int、Long類型)如何在JavaScript中進行二進制轉換,如果感興趣的可以可以閱讀本系列第二篇博客——WebSocket系列之JavaScript中數字數據如何轉換爲二進制數據。這次,我們來說下string類型的數據如何進行處理。
本文是WebSocket系列的第三篇,主要介紹string數據與二進制數據之間的轉換方法,具體的內容如下:

  • JavaScript中string類型基礎知識
  • JavaScript如何將string類型轉換爲二進制數據
  • JavaScript如何將二進制數據轉換爲string類型
    本文與WebSocket並無太強關聯,不過作爲在WebSocket中傳遞二進制數據的基礎知識儲備,因此放入了此係列當中。
    如果讀者對WebSocket並不瞭解,或者說不明白它的使用場景和細節,可以閱讀我的本系列的第一篇博客——WebSocket系列之基礎知識入門篇

string類型基礎知識

string這個類型,對於熟悉JavaScript的同學應該都不陌生,它是屬於JavaScript中基礎數據類型的一種。不過,我們今天要先介紹下DOMString

DOMString 是一個UTF-16字符串。由於JavaScript已經使用了這樣的字符串,所以DOMString 直接映射到 一個String。將null傳遞給接受DOMString的方法或參數時通常會把其轉換成爲“null”。

在WebSocket中進行string類型數據傳輸時,使用的其實也是DOMString。不過,根據MDN中對DOMString的介紹我們可以瞭解到,大部分日常使用場景中,我們可以認爲DOMString就是一個string類型。所以,我們只需要瞭解此類型,使用時仍然當成string類型處理即可。

編碼

既然上面提到了UTF-16,那麼我們就來簡單介紹下UTF-16,以及後端常用的UTF-8這兩種編碼方式。
爲什麼需要介紹編碼類型呢?因爲我們在與後端進行字符串數據傳遞時,可能使用的編碼方式不同,這樣就會導致雙方得到不同的數據。因此,我們在進行string的二進制數據通信時,不僅僅需要將字符串轉換成二進制,還需要協商一致的string編碼。

UTF-16

UTF-16 (16-bit Unicode Transformation Format) 是Unicode字符編碼五層次模型的第三層:字符編碼表(Character Encoding Form,也稱爲"storage format")的一種實現方式。即把Unicode字符集的抽象碼位映射爲16位長的整數(即碼元)的序列,用於數據存儲或傳遞。
Unicode字符的碼位,需要1個或者2個16位長的碼元來表示,因此這是一個變長表示。

UTF-16是JavaScript中的string編碼類型。

UTF-8

UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,也是一種前綴碼。它可以用來表示Unicode標準中的任何字元,且其編碼中的第一個字節仍與ASCII兼容,這使得原來處理ASCII字元的軟件無須或只須做少部分修改,即可繼續使用。UTF-8使用一至四個字節爲每個字符編碼(2003年11月重新規範)。

UTF-8是很多語言使用的通用編碼類型,在後端應用中非常常見。

JavaScript中UTF16和UTF-8如何進行編碼轉換

在Github上有轉換庫GitHub - dcodeIO/utfx: A compact library to encode, decode and convert UTF8 / UTF16 in JavaScript.,通過這個庫,可以將字符串在UTF-8編碼和UTF-16編碼中進行轉換。該庫的具體原理和內容以及兩種編碼方式的詳細內容說明將會在之後的博客中進行講解。我們下面簡單的介紹下它是使用方式:

import utfx from './util/utfx';

let str = 'abcdefg';
let result = [];

function stringSource(s) {
    let i = 0;
    return function () {
        return i < s.length ? s.charCodeAt(i++) : null;
    };
}

utfx.encodeUTF16toUTF8(stringSource(str), function (b) {
    result.push(b);
}.bind(this));

同理,該類庫提供了其他的方法:

  • decodeUTF8toUTF16,將UTF-8的string數據轉換爲UTF-16的string數據。
  • calculateUTF16asUTF8,計算UTF-16編碼的string類型類型轉換爲UTF-8後所佔Byte長度。
    這兩個方法我們在之後的章節中也會用到。

JavaScript如何將string類型轉換爲二進制數據

瞭解了JavaScript中string類型的編碼和在UTF-8和UTF-16之間轉換編碼的方式,下面我們來看下如何將string類型轉換爲二進制數據。
首先,我們假定與後端交互時使用的編碼方式爲UTF-8,這樣能夠滿足更多的使用場景。如果仍然使用UTF-16的話,則直接忽略轉換編碼的邏輯即可。
簡單介紹下實現思路:我們得到一個需要轉換的字符串後,先知道其長度後,初始化ArrayBuffer中相關參數,將數據放入ArrayBuffer中即可。我們將上面的示例稍作改動:

import utfx from './util/utfx';

function stringSource(s) {
    var i = 0;
    return function () {
        return i < s.length ? s.charCodeAt(i++) : null;
    };
}

let str = 'abcdefg';

let strCodes = stringSource(str);
let length = utfx.calculateUTF16asUTF8(strCodes)[1];
let buffer = new ArrayBuffer(length + 4); // 初始化長度爲UTF8編碼後字符串長度+4個Byte的二進制緩衝區
let view = new DataView(buffer);
let offset = 4;

view.setUint32(0, length); // 將長度放置在字符串的頭部

utfx.encodeUTF16toUTF8(stringSource(str), function (b) {
    view.setUint8(offset++, b);
}.bind(this));

通過上面的示例,我們就已經將一個二進制數據根據UTF-8編碼後放入了ArrayBuffer中,同時,將其長度作爲一個Unsigned Int類型存儲在了二進制頭部4個Byte的位置。

JavaScript如何將二進制數據轉換爲string類型

知道了如何將string類型轉換爲二進制數據,下面我們看下如何將整個數據從二進制中讀取,轉換回string類型。
根據上面轉換爲二進制的過程,我們不難想到相關的二進制轉string類型方法。具體示例如下:

import utfx from './util/utfx';
let str = 'abcdefg';

function stringSource(s) {
    var i = 0;
    return function () {
        return i < s.length ? s.charCodeAt(i++) : null;
    };
}

let strCodes = stringSource(str);
let length = utfx.calculateUTF16asUTF8(strCodes)[1];
let buffer = new ArrayBuffer(length + 4); // 初始化長度爲UTF8編碼後字符串長度+4個Byte的二進制緩衝區
let view = new DataView(buffer);
let offset = 4;

// 字符串轉換二進制過程
view.setUint32(0, length); // 將長度放置在字符串的

utfx.encodeUTF16toUTF8(stringSource(str), function (b) {
    view.setUint8(offset++, b);
}.bind(this));

// 二進制轉換字符串過程
let Strlength = view.getUint32(0);
offset = 4;
let result = []; // Unicode編碼字符
let end = offset + Strlength;


utfx.decodeUTF8toUTF16(function () {
    return offset < end ? view.getUint8(offset++) : null; // 返回null時會退出此轉換函數
}.bind(this), (char) => {
    console.log(char)
    result.push(char);
});

let strResult = result.reduce((prev, next)=>{
    return prev + String.fromCharCode(next);
}, '');

通過上面的示例我們可以知道,我們只需要在前面4個Byte中將字符串長度讀取出來,然後再從第4個Byte(從0開始算)的位置開始讀取指定長度的字符串字符編碼即可。最後,我們得到了一個Unicode碼數組,只需要fromCharCode方法即可將其轉換爲字符串。

總結

通過使用ArrayBuffer和DataView,我們能夠在string數據和二進制數據中進行互相轉換。
有了string類型轉換的相關基礎,讀者就能夠在之後的WebSocket進行二進制數據傳遞時理解相關的內容和處理邏輯。
下一篇WebSocket系列相關的博客,將會介紹如何通過WebSocket來向後端傳遞二進制數據,以及如何處理通過WebSocket收到的二進制數據。有興趣的同學可以繼續關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章