NodeJSバイナリバッファーをJavaScript ArrayBufferに変換するにはどうすればよいですか?
Array
。したがって、多くの浮動小数点Float32Array
数を格納するには、4バイトかかる場所が必要です。また、Buffer
JSONへのシリアル化には時間がかかるため、これらのフロートをファイルにすばやくシリアル化する場合は、が必要です。
NodeJSバイナリバッファーをJavaScript ArrayBufferに変換するにはどうすればよいですか?
Array
。したがって、多くの浮動小数点Float32Array
数を格納するには、4バイトかかる場所が必要です。また、Buffer
JSONへのシリアル化には時間がかかるため、これらのフロートをファイルにすばやくシリアル化する場合は、が必要です。
回答:
のインスタンスはBuffer
Uint8Array
、node.js 4.x以降のインスタンスでもあります。したがって、最も効率的なソリューションはbuf.buffer
、https://stackoverflow.com/a/31394257/1375574に従って、プロパティに直接アクセスすることです。他の方向に進む必要がある場合、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からBufferへ:
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;
}
size&0xfffffffe
、32ビット整数をコピーし、残りが1バイトの場合は8ビット整数をコピーし、2バイトの場合は16ビット整数をコピーし、3バイトの場合は16ビットと8ビット整数をコピーします。
ab
返されるのですか?何もしていab
ませんか?私はいつも{}
結果として得ます。
slice()
メソッドは、ArrayBuffer
内容ArrayBuffer
の先頭から両端までのこのバイトのコピーを含むnew を返します。- MDNArrayBuffer.prototype.slice()
Buffer
sはUint8Array
sなので、バッキングのその領域をスライス(コピー)するだけですArrayBuffer
。
// Original Buffer
let b = Buffer.alloc(512);
// Slice (copy) its segment of the underlying ArrayBuffer
let ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
slice
オフセットものがされている必要小さいのでBuffer
(デフォルト、半分未満の4kBのプールサイズは)共有上でビューすることができますArrayBuffer
。スライスしないと、ArrayBuffer
別のからのデータが含まれることになりますBuffer
。ドキュメントの説明を参照してください。
最終的にが必要な場合はTypedArray
、データをコピーせずにを作成できます。
// Create a new view of the ArrayBuffer without copying
let ui32 = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / Uint32Array.BYTES_PER_ELEMENT);
O(n)時間で実行されるMartin Thomsonの回答を使用します。(非最適化についての彼の回答に対するコメントへの私の返信も参照してください。DataViewの使用は遅いです。バイトをフリップする必要がある場合でも、より高速な方法があります。)
https://www.npmjs.com/package/memcpyを使用して、どちらの方向にも移動できます(バッファーからArrayBufferへ、およびその逆)。ここに掲載されている他の回答よりも速く、よく書かれたライブラリです。ノード0.12からiojs 3.xまでは、ngossenのフォークが必要です(これを参照)。
.byteLength
し、.byteOffset
文書化?
var ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
私の日を救った
「ArrayBufferからBufferへ」は次のように実行できます。
var buffer = Buffer.from( new Uint8Array(ab) );
それを書くためのより速い方法
var arrayBuffer = new Uint8Array(nodeBuffer).buffer;
ただし、これは、1024要素のバッファーで推奨されるtoArrayBuffer関数よりも約4倍遅く実行されるようです。
Buffer
インスタンスはUint8Array
Node.js 4.x以降ののインスタンスでもある。Node.jsの下位バージョンでは、toArrayBuffer
関数を実装する必要があります。
Buffer
はを調べるための単なるビューですArrayBuffer
。AはBuffer
、実際には、ありFastBuffer
、そのextends
(から継承)Uint8Array
オクテット単位であり、ビュー実際のメモリ(「部分アクセッサ」) ArrayBuffer
。
/lib/buffer.js#L65-L73
class FastBuffer extends Uint8Array {
constructor(arg1, arg2, arg3) {
super(arg1, arg2, arg3);
}
}
FastBuffer.prototype.constructor = Buffer;
internalBuffer.FastBuffer = FastBuffer;
Buffer.prototype = FastBuffer.prototype;
ArrayBuffer
そのビューのサイズは異なる場合があります。Buffer.from(arrayBuffer[, byteOffset[, length]])
。ではBuffer.from(arrayBuffer[, byteOffset[, length]])
、あなたが作成することができBuffer
、その基礎となる指定してArrayBuffer
、ビューの位置とサイズを。
const test_buffer = Buffer.from(new ArrayBuffer(50), 40, 10);
console.info(test_buffer.buffer.byteLength); // 50; the size of the memory.
console.info(test_buffer.length); // 10; the size of the view.
FastBuffer
のメモリ割り当て。サイズに応じて、2つの異なる方法でメモリを割り当てます。
ArrayBuffer
必要なメモリに正確に適合する専用を作成します。/lib/buffer.js#L306-L320
9.4.0
function allocate(size) {
if (size <= 0) {
return new FastBuffer();
}
if (size < (Buffer.poolSize >>> 1)) {
if (size > (poolSize - poolOffset))
createPool();
var b = new FastBuffer(allocPool, poolOffset, size);
poolOffset += size;
alignPool();
return b;
} else {
return createUnsafeBuffer(size);
}
}
📜/lib/buffer.js#L98-L100
9.4.0
function createUnsafeBuffer(size) {
return new FastBuffer(createUnsafeArrayBuffer(size));
}
メモリプールは、固定サイズであり、事前に割り当てられたため、小さなサイズのメモリチャンクを保持するためのメモリブロックBuffer
S。これを使用すると、小さなサイズのメモリチャンクが密に保持されるため、個別の管理(割り当てと割り当て解除)によって引き起こされる断片化がされます。
この場合、メモリプールはArrayBuffer
デフォルトで8 KiBのサイズで、で指定されていBuffer.poolSize
ます。に小さなサイズのメモリチャンクを提供するBuffer
場合、最後のメモリプールにこれを処理するのに十分な使用可能メモリがあるかどうかをチェックします。もしそうなら、それが作成しBuffer
、その「意見を」は、メモリプールの指定された部分的なチャンクます。それ以外の場合は、新しいメモリプールを作成します。
の基礎ArrayBuffer
にアクセスできますBuffer
。プロパティ(から継承されている、)それを保持しています。「小さな」のプロパティがあるメモリプール全体を表しています。したがって、この場合、およびはサイズが異なります。Buffer
buffer
Uint8Array
Buffer
buffer
ArrayBuffer
ArrayBuffer
Buffer
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
// A `Buffer`'s `length` property holds the size, in octets, of the view.
// An `ArrayBuffer`'s `byteLength` property holds the size, in octets, of its data.
console.info(zero_sized_buffer.length); /// 0; the view's size.
console.info(zero_sized_buffer.buffer.byteLength); /// 0; the memory..'s size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(small_buffer.length); /// 3; the view's size.
console.info(small_buffer.buffer.byteLength); /// 8192; the memory pool's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
console.info(big_buffer.length); /// 4096; the view's size.
console.info(big_buffer.buffer.byteLength); /// 4096; the memory's size.
console.info(Buffer.poolSize); /// 8192; a memory pool's size.
ArrayBuffer
サイズは固定なので、我々は一部のコピーを作成することにより、それを抽出する必要があります。これを行うには、から継承されるBuffer
のbyteOffset
プロパティとlength
プロパティUint8Array
、およびのArrayBuffer.prototype.slice
一部のコピーを作成するメソッドを使用しますArrayBuffer
。ここでのslice()
-ingメソッドは@ZachBに触発されました。
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function extract_arraybuffer(buf)
{
// You may use the `byteLength` property instead of the `length` one.
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
}
// A copy -
const test_arraybuffer = extract_arraybuffer(test_buffer); // of the memory.
const zero_sized_arraybuffer = extract_arraybuffer(zero_sized_buffer); // of the... void.
const small_arraybuffer = extract_arraybuffer(small_buffer); // of the part of the memory.
const big_arraybuffer = extract_arraybuffer(big_buffer); // of the memory.
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096
結果を読み取り専用として使用する場合、または入力Buffer
の内容を変更しても問題ない場合は、不要なメモリのコピーを回避できます。
const test_buffer = Buffer.from(new ArrayBuffer(10));
const zero_sized_buffer = Buffer.allocUnsafe(0);
const small_buffer = Buffer.from([0xC0, 0xFF, 0xEE]);
const big_buffer = Buffer.allocUnsafe(Buffer.poolSize >>> 1);
function obtain_arraybuffer(buf)
{
if(buf.length === buf.buffer.byteLength)
{
return buf.buffer;
} // else:
// You may use the `byteLength` property instead of the `length` one.
return buf.subarray(0, buf.length);
}
// Its underlying `ArrayBuffer`.
const test_arraybuffer = obtain_arraybuffer(test_buffer);
// Just a zero-sized `ArrayBuffer`.
const zero_sized_arraybuffer = obtain_arraybuffer(zero_sized_buffer);
// A copy of the part of the memory.
const small_arraybuffer = obtain_arraybuffer(small_buffer);
// Its underlying `ArrayBuffer`.
const big_arraybuffer = obtain_arraybuffer(big_buffer);
console.info(test_arraybuffer.byteLength); // 10
console.info(zero_sized_arraybuffer.byteLength); // 0
console.info(small_arraybuffer.byteLength); // 3
console.info(big_arraybuffer.byteLength); // 4096
obtain_arraybuffer
:buf.buffer.subarray
存在していないようです。もしかしてbuf.buffer.slice
ここ?
ArrayBuffer.prototype.slice
、後でに変更しましたUint8Array.prototype.subarray
。ああ、私はそれを間違った。おそらく、当時は少し混乱していました。あなたのおかげで、今はすべて順調です。
次の優れたnpmパッケージを使用してくださいto-arraybuffer
。
または、自分で実装することもできます。バッファーが呼び出された場合はbuf
、次のようにします。
buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
ArrayBuffer
は型付きと考えることができますBuffer
。
ArrayBuffer
したがって、常にタイプ(いわゆる「アレイバッファービュー」)を必要とします。通常、配列バッファビューには、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!"
上記の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++;
}
Buffer.read*
方法はまた、すべての遅いです。
このプロキシは、コピーなしで、バッファをTypedArrayのいずれかとして公開します。:
https://www.npmjs.com/package/node-buffer-as-typedarray
LEでのみ機能しますが、BEに簡単に移植できます。また、これがどれほど効率的かを実際にテストする必要はありません。
これに非常に便利なnpmパッケージがあります:https : buffer
//github.com/feross/buffer
ノードのバッファAPIと100%同一のAPIを提供し、以下を許可しようとします。
そしていくつか。
NodeJSは、ある時点で(v0.6.xだったと思います)、ArrayBufferをサポートしていました。ここでbase64エンコードおよびデコード用の小さなライブラリを作成しましたが、v0.7に更新してから、(NodeJSでの)テストが失敗します。これを正規化するものを作ろうと思っていますが、それまではNodeのネイティブをBuffer
使うべきだと思います。
私はすでにノードをバージョン5.0.0に更新しており、これを使用して作業します。
function toArrayBuffer(buffer){
var array = [];
var json = buffer.toJSON();
var list = json.data
for(var key in list){
array.push(fixcode(list[key].toString(16)))
}
function fixcode(key){
if(key.length==1){
return '0'+key.toUpperCase()
}else{
return key.toUpperCase()
}
}
return array
}
私はそれを使って私のvhdディスクイメージをチェックします。
toArrayBuffer(new Buffer([1,2,3]))
-> ['01', '02', '03']
-これは整数/バイトではなく、文字列の配列を返します。