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

Renato Mangini

ArrayBuffers は元データの転送に使用されており、WebSocketsウェブ インテント 2](https://www.html5rocks.com/en/tutorials/file/xhr2/)、WebWorkers などの新しい API でも使用されています。しかし、最近 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 に関して、String から ArrayBuffer へ、またはその逆への変換方法はよく出てきます。ArrayBuffer は実際にはバイト配列であるため、この変換では、String の文字をバイトとして表現する方法が両端で一致している必要があります。この「合意」はご存じのことと思います。これは String の文字エンコードです(また、通常の「合意用語」は 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 を作成し、String を含む Blob をフィードします。この方法は機能しますが、読みにくく、動作に時間がかかる可能性があります。根拠のない疑いが人類の歴史に多くのミスを生んだため、ここではより科学的なアプローチを見てみましょう。2 つのメソッドについて jsperf を実行したところ、私の疑念が確認できました。こちらのデモをご覧ください

Chrome 20 では、この記事で直接 ArrayBuffer 操作コードを使用する方が、FileReader/Blob メソッドを使用するよりも約 27 倍高速です。