web-dev-qa-db-de.com

Konvertieren Sie einen binären NodeJS-Puffer in JavaScript ArrayBuffer

Wie kann ich einen NodeJS-Binärpuffer in einen JavaScript-ArrayBuffer konvertieren?

96
Drake Amara

Instanzen von Buffer sind auch Instanzen von Uint8Array in node.js 4.x und höher. Daher ist die effizienteste Lösung der direkte Zugriff auf die buf.buffer-Eigenschaft gemäß https://stackoverflow.com/a/31394257/1375574 . Der Pufferkonstruktor benötigt auch ein ArrayBufferView-Argument, wenn Sie in die andere Richtung gehen müssen.

Beachten Sie, dass dadurch keine Kopie erstellt wird. Dies bedeutet, dass das Schreiben in ein ArrayBufferView in die ursprüngliche Buffer-Instanz durchgeht.


In älteren Versionen enthält node.js beide ArrayBuffer als Teil von v8, die Pufferklasse bietet jedoch eine flexiblere API. Zum Lesen oder Schreiben in einen ArrayBuffer müssen Sie lediglich eine Ansicht erstellen und across kopieren.

Vom Puffer zum 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;
}

Vom ArrayBuffer zum Puffer:

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;
}
91
Martin Thomson
  • Keine Abhängigkeiten, am schnellsten, Knoten 4.x und höher

Puffer sind Uint8Arrays, Sie müssen also nur auf ihren ArrayBuffer zugreifen. Dies ist 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);

Die Variable slice und offset ist required, da kleine Puffer (<4096 Byte, glaube ich) Ansichten eines gemeinsam genutzten ArrayBuffer sind. Andernfalls erhalten Sie möglicherweise einen ArrayBuffer, der Daten eines anderen TypedArray enthält.

  • Keine Abhängigkeiten, moderate Geschwindigkeit, beliebige Version des Knotens

Verwenden Sie Martin Thomsons Antwort , die in O(n) Zeit läuft. (Siehe auch meine Antworten auf Kommentare zu seiner Antwort zu Nicht-Optimierungen. Die Verwendung einer DataView ist langsam. Selbst wenn Sie Bytes umkehren müssen, gibt es schnellere Möglichkeiten.)

  • Abhängigkeit, schnell, jede Version des Knotens

Sie können https://www.npmjs.com/package/memcpy verwenden, um in beide Richtungen zu gehen (Puffer zu ArrayBuffer und zurück). Es ist schneller als die anderen hier veröffentlichten Antworten und ist eine gut geschriebene Bibliothek. Knoten 0.12 bis iojs 3.x benötigen die Gabel von ngossen (siehe this ).

46
ZachB

"From ArrayBuffer to Buffer" könnte folgendermaßen ausgeführt werden: 

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

Ein schneller Weg, um es zu schreiben

var arrayBuffer = new Uint8Array(nodeBuffer).buffer;

Dies scheint jedoch etwa viermal langsamer zu sein als die vorgeschlagene toArrayBuffer-Funktion in einem Puffer mit 1024 Elementen.

23
David Fooks

Verwenden Sie das folgende ausgezeichnete npm-Paket: to-arraybuffer .

Oder Sie können es selbst implementieren. Wenn Ihr Puffer buf heißt, gehen Sie folgendermaßen vor:

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

Sie können sich eine ArrayBuffer als typisierte Buffer vorstellen. 

Eine ArrayBuffer benötigt daher immer einen Typ (die sogenannte "Array Buffer View"). Normalerweise hat die Array-Pufferansicht den Typ Uint8Array oder Uint16Array.

Von Renato Mangini gibt es einen guten Artikel zur Konvertierung zwischen einem ArrayBuffer und einem String .

Ich habe die wesentlichen Teile in einem Codebeispiel (für Node.js) zusammengefasst. Es zeigt auch, wie zwischen der typisierten ArrayBuffer und der nicht typisierten Buffer konvertiert wird.

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

Ich habe das oben für ein Float64Array ausprobiert und es hat einfach nicht funktioniert.

Am Ende wurde mir klar, dass die Daten wirklich "INTO" der Ansicht in korrekten Blöcken gelesen werden mussten. Dies bedeutet, dass jeweils 8 Bytes aus dem Quellpuffer gelesen werden.

Jedenfalls bin ich damit fertig geworden ...

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

Dieser Proxy macht den Puffer als eine der TypedArrays ohne Kopie verfügbar. : 

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

Es funktioniert nur bei LE, kann aber problemlos auf BE ..__ portiert werden. Außerdem wurde nie wirklich getestet, wie effizient dies ist.

0
Dlabz