Come convertire Arraybuffer in e da String

Renato Mangini

Gli ArrayBuffers vengono utilizzati per trasportare dati non elaborati e li utilizzano diverse nuove API, tra cui WebSockets, Web Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/) e WebWorkers. Tuttavia, poiché recentemente si sono imbattute nel mondo JavaScript, a volte vengono interpretate o utilizzate in modo improprio.

Dal punto di vista semantico, ArrayBuffer è semplicemente un array di byte visualizzati attraverso una maschera specifica. Questa maschera, un'istanza di ArrayBufferView, definisce il modo in cui i byte sono allineati per corrispondere alla struttura prevista dei contenuti. Ad esempio, se sai che i byte in un ArrayBuffer rappresentano un array di numeri interi senza segno a 16 bit, puoi eseguire il wrapping di ArrayBuffer in una vista Uint16Array e puoi manipolarne gli elementi utilizzando la sintassi delle parentesi come se Uint16Array fosse un array con numeri interi:

// suppose buf contains the bytes [0x02, 0x01, 0x03, 0x07]
// notice the multibyte values respect the hardware endianess, which is little-endian in x86
var bufView = new Uint16Array(buf);
if (bufView[0]===258) {   // 258 === 0x0102
    console.log("ok");
}
bufView[0] = 255;    // buf now contains the bytes [0xFF, 0x00, 0x03, 0x07]
bufView[0] = 0xff05; // buf now contains the bytes [0x05, 0xFF, 0x03, 0x07]
bufView[1] = 0x0210; // buf now contains the bytes [0x05, 0xFF, 0x10, 0x02]

Una domanda pratica comune su ArrayBuffer è come convertire un String in un ArrayBuffer e viceversa. Poiché ArrayBuffer è in realtà un array di byte, questa conversione richiede che entrambe le estremità siano d'accordo sul modo in cui rappresentare i caratteri nella stringa come byte. Probabilmente hai già visto questo "contratto": è la codifica dei caratteri della stringa (e i soliti "termini del contratto" sono, ad esempio, Unicode UTF-16 e iso8859-1). Supponendo che tu e l'altra parte abbiate concordato la codifica UTF-16, il codice di conversione potrebbe essere simile al seguente:

function ab2str(buf) {
    return String.fromCharCode.apply(null, new Uint16Array(buf));
}
function str2ab(str) {
    var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
    var bufView = new Uint16Array(buf);
    for (var i=0, strLen=str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

Tieni presente l'utilizzo di Uint16Array. Questa è una visualizzazione di ArrayBuffer che allinea i byte di ArrayBuffers come elementi a 16 bit. Non gestisce la codifica dei caratteri autonoma, che viene gestita come Unicode da String.fromCharCode e str.charCodeAt.

Una domanda molto comune di StackOverflow ha una risposta molto votata con una soluzione un po' contorta della conversione: crea una FileReader da utilizzare come convertitore e inserisci al suo interno un elemento Blob contenente la stringa. Sebbene questo metodo funzioni, ha una scarsa leggibilità e suppongo che sia lento. Poiché sospetti infondati hanno causato molti errori nella storia dell'umanità, adottiamo un approccio più scientifico. Ho verificato i due metodi e il risultato conferma il mio sospetto. Guarda la demo qui.

In Chrome 20, l'utilizzo del codice di manipolazione diretto ArrayBuffer in questo articolo è quasi 27 volte più veloce rispetto all'utilizzo del metodo FileReader/Blob.