web-dev-qa-db-ja.com

バイナリNodeJSバッファーをJavaScript ArrayBufferに変換する

NodeJSバイナリバッファーをJavaScript ArrayBufferに変換するにはどうすればよいですか?

111
Drake Amara

BufferのインスタンスはUint8Arrayのインスタンスでもあります node.js 4.x以降では。したがって、最も効率的なソリューションは、 https://stackoverflow.com/a/31394257/1375574 に従って、buf.bufferプロパティに直接アクセスすることです。他の方向に進む必要がある場合、BufferコンストラクターはArrayBufferView引数も取ります。

これはコピーを作成しないことに注意してください。つまり、ArrayBufferViewに書き込むと、元のBufferインスタンスに書き込みが行われます。


バッファーからArrayBufferへ:

function toArrayBuffer(buf) {
    var ab = new ArrayBuffer(buf.length);
    var view = new Uint8Array(ab);
    for (var i = 0; i < buf.length; ++i) {
        view[i] = buf[i];
    }
    return ab;
}

ArrayBufferからバッファへ:

function toBuffer(ab) {
    var buf = Buffer.alloc(ab.byteLength);
    var view = new Uint8Array(ab);
    for (var i = 0; i < buf.length; ++i) {
        buf[i] = view[i];
    }
    return buf;
}
110
Martin Thomson
  • 依存関係なし、最速、ノード4.x以降

バッファーはUint8Arrayであるため、ArrayBufferにアクセスするだけです。これはO(1)

 // node buffer
var b = new Buffer(512);
 // ArrayBuffer
var ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
 // TypedArray
var ui32 = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / Uint32Array.BYTES_PER_ELEMENT);

sliceとoffset stuffはrequiredです。なぜなら、小さなバッファー(<4096バイト、私は思う)は共有ArrayBuffer上のビューだからです。これがないと、別のTypedArrayからのデータを含むArrayBufferになってしまう可能性があります。

  • 依存関係なし、中程度の速度、ノードのすべてのバージョン

Martin Thomson's answer を使用します。これはO(n)時間で実行されます。 (非最適化についての彼の答えに対するコメントへの私の回答も参照してください。DataViewの使用は遅いです。バイトを反転する必要がある場合でも、それを行うより速い方法があります。)

  • 依存関係、高速、ノードの任意のバージョン

https://www.npmjs.com/package/memcpy を使用して、どちらの方向にも移動できます(Buffer to ArrayBufferおよびback)。ここに投稿された他の回答よりも高速で、よく書かれたライブラリです。 Node 0.12〜iojs 3.xには、ngossenのフォークが必要です( this を参照)。

52
ZachB

「ArrayBufferからバッファへ」は次の方法で実行できます。

var buffer = Buffer.from( new Uint8Array(ab) );
46
kraag22

より簡単な書き方

var arrayBuffer = new Uint8Array(nodeBuffer).buffer;

ただし、これは、1024個の要素を持つバッファーで推奨されるtoArrayBuffer関数よりも約4倍遅いように見えます。

25
David Fooks

次の優れたnpmパッケージを使用してください: to-arraybuffer

または、自分で実装することもできます。バッファの名前がbufの場合、これを実行します。

buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
12
Feross

ArrayBufferは、型付きのBufferと考えることができます。

したがって、ArrayBufferには常に型が必要です(いわゆる「配列バッファービュー」)。通常、Array Buffer ViewのタイプはUint8ArrayまたはUint16Arrayです。

ArrayBufferとString間の変換 にRenato Manginiからの良い記事があります。

コード例で重要な部分を要約しました(Node.jsの場合)。また、型付きArrayBufferと型なしBufferの間の変換方法も示します。

function stringToArrayBuffer(string) {
  const arrayBuffer = new ArrayBuffer(string.length);
  const arrayBufferView = new Uint8Array(arrayBuffer);
  for (let i = 0; i < string.length; i++) {
    arrayBufferView[i] = string.charCodeAt(i);
  }
  return arrayBuffer;
}

function arrayBufferToString(buffer) {
  return String.fromCharCode.apply(null, new Uint8Array(buffer));
}

const helloWorld = stringToArrayBuffer('Hello, World!'); // "ArrayBuffer" (Uint8Array)
const encodedString = new Buffer(helloWorld).toString('base64'); // "string"
const decodedBuffer = Buffer.from(encodedString, 'base64'); // "Buffer"
const decodedArrayBuffer = new Uint8Array(decodedBuffer).buffer; // "ArrayBuffer" (Uint8Array)

console.log(arrayBufferToString(decodedArrayBuffer)); // prints "Hello, World!"
1

Float64Arrayに対して上記を試しましたが、うまくいきませんでした。

私は、データを正しいチャンクで「INTO」ビューに読み込む必要があることに気付きました。これは、ソースバッファから一度に8バイトを読み取ることを意味します。

とにかく、これは私が終わったものです...

var buff = new Buffer("40100000000000004014000000000000", "hex");
var ab = new ArrayBuffer(buff.length);
var view = new Float64Array(ab);

var viewIndex = 0;
for (var bufferIndex=0;bufferIndex<buff.length;bufferIndex=bufferIndex+8)            {

    view[viewIndex] = buff.readDoubleLE(bufferIndex);
    viewIndex++;
}
0
Exitos

このプロキシは、バッファをコピーせずにTypedArrayのいずれかとして公開します。 :

https://www.npmjs.com/package/node-buffer-as-typedarray

LEでのみ動作しますが、BEに簡単に移植できます。また、これがどれほど効率的かを実際にテストすることもありません。

0
Dlabz