Wie kann ich einen NodeJS-Binärpuffer in einen JavaScript-ArrayBuffer konvertieren?
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.
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;
}
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.
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.)
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 ).
"From ArrayBuffer to Buffer" könnte folgendermaßen ausgeführt werden:
var buffer = Buffer.from( new Uint8Array(ab) );
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.
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)
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!"
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++;
}
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.