ArrayBuffer と String の間で変換する方法

ArrayBuffer は未加工データを転送するために使用され、WebSocketsWeb Intents 2](https://www.html5rocks.com/en/tutorials/file/xhr2/)、WebWorkers など、いくつかの新しい API が ArrayBuffer に依存しています。ただし、JavaScript の世界に登場したばかりであるため、誤解や誤用されることがあります。

意味的には、ArrayBuffer は、特定のマスクで表示されるバイトの配列にすぎません。このマスク(ArrayBufferView のインスタンス)は、コンテンツの想定される構造に合わせてバイトがどのように配置されるかを定義します。たとえば、ArrayBuffer 内のバイトが 16 ビットの符号なし整数の配列を表していることがわかっている場合は、ArrayBuffer を Uint16Array ビューでラップするだけで、Uint16Array が整数配列であるかのようにかっこ構文を使用して要素を操作できます。

// 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]

ArrayBuffer に関する一般的な実践的な質問の 1 つは、StringArrayBuffer に変換する方法とその逆です。ArrayBuffer は実際にはバイト配列であるため、この変換では、文字列内の文字をバイトとして表す方法について両端で合意する必要があります。この「契約」は、文字列の文字エンコードです(通常の「契約条項」は、Unicode UTF-16 や iso8859-1 などです)。したがって、お客様と相手方が UTF-16 エンコードに同意している場合、変換コードは次のようになります。

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;
}

Uint16Array の使用に注意してください。これは、ArrayBuffer のバイト数を 16 ビット要素としてアライメントする ArrayBuffer ビューです。文字エンコード自体は処理しません。これは String.fromCharCodestr.charCodeAt によって Unicode として処理されます。

StackOverflow のこの問題に関するよくある質問には、変換に関するやや複雑な解決策が記載された、高評価の回答があります。変換元として機能する FileReader を作成し、文字列を含む Blob をそれにフィードします。この方法は機能しますが、可読性が低く、遅いと思われます。根拠のない疑惑が人類の歴史において多くの間違いを引き起こしてきたため、ここではより科学的なアプローチをとることにしましょう。2 つのメソッドを jsperf でテストした結果、私の疑念が確認されました。デモはこちらで確認できます。

Chrome 20 では、この記事の直接 ArrayBuffer 操作コードを使用すると、FileReader/Blob メソッドを使用する場合と比べてほぼ 27 倍高速になります。