Wie kann ich einen NodeJS-Binärpuffer in einen JavaScript-ArrayBuffer konvertieren?
Konvertieren Sie einen binären NodeJS-Puffer in einen JavaScript-ArrayBuffer
Drake Amara
Martin Thompson
Instanzen von Buffer
sind auch Fälle von Uint8Array
in node.js 4.x und höher. Daher ist die effizienteste Lösung der Zugriff auf die buf.buffer
Eigenschaft direkt, gemäß https://stackoverflow.com/a/31394257/1375574. Der Buffer-Konstruktor akzeptiert auch ein ArrayBufferView-Argument, wenn Sie in die andere Richtung gehen müssen.
Beachten Sie, dass dadurch keine Kopie erstellt wird, was bedeutet, dass Schreibvorgänge in eine beliebige ArrayBufferView in die ursprüngliche Buffer-Instanz durchschreiben.
In älteren Versionen hat node.js sowohl ArrayBuffer als Teil von v8, aber die Buffer-Klasse bietet eine flexiblere API. Um einen ArrayBuffer zu lesen oder zu schreiben, müssen Sie nur eine Ansicht erstellen und hinüber kopieren.
Von Buffer zu ArrayBuffer:
function toArrayBuffer(buf) {
const ab = new ArrayBuffer(buf.length);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
view[i] = buf[i];
}
return ab;
}
Von ArrayBuffer zu Buffer:
function toBuffer(ab) {
const buf = Buffer.alloc(ab.byteLength);
const view = new Uint8Array(ab);
for (let i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
-
Ich würde Ihnen auch empfehlen, dies zu optimieren, indem Sie nach Möglichkeit Ganzzahlen mit DataView kopieren. Noch bis
size&0xfffffffe
kopieren Sie 32-Bit-Ganzzahlen, kopieren Sie dann, wenn 1 Byte übrig ist, 8-Bit-Ganzzahlen, kopieren Sie 16-Bit-Ganzzahlen, wenn 2 Bytes vorhanden sind, und kopieren Sie 16-Bit- und 8-Bit-Ganzzahlen, wenn 3 Bytes übrig sind.– Triang3l
13. Februar 2013 um 17:25 Uhr
-
Siehe die Antwort von kraag22 für eine einfachere Implementierung der Hälfte davon.
– Orangenhund
20. Juni 2013 um 16:47 Uhr
-
Habe Buffer -> ArrayBuffer mit einem für den Browser gedachten Modul getestet und es funktioniert hervorragend. Danke!
– evtl
26. Mai 2014 um 2:49 Uhr
-
Warum ist
ab
ist zurückgekommen? Es wird nichts damit gemachtab
? Ich bekomme immer{}
als Ergebnis.– Andi Giga
7. Juli 2016 um 15:09 Uhr
-
‘Die
slice()
Methode gibt eine neue zurückArrayBuffer
dessen Inhalt eine Kopie davon istArrayBuffer
‘s Bytes von Anfang, inklusive, bis Ende, exklusiv.’ – MDNArrayBuffer.prototype.slice()
– Константин Ван
23. Januar 2018 um 19:01 Uhr
ZachB
Keine Abhängigkeiten, am schnellsten, Node.js 4.x und höher
Buffer
s sind Uint8Array
s, also müssen Sie nur seinen Bereich des Trägers schneiden (kopieren). 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);
Die slice
und Offset-Zeug ist erforderlich weil klein Buffer
s (standardmäßig weniger als 4 kB, die Hälfte der Pool Größe) können Ansichten auf einem Shared sein ArrayBuffer
. Ohne Aufschneiden können Sie mit einem enden ArrayBuffer
Daten von einem anderen enthalten Buffer
. Sehen Erklärung in den Dokumenten.
Wenn Sie letztendlich eine benötigen TypedArray
können Sie eine erstellen, ohne die Daten zu kopieren:
// Create a new view of the ArrayBuffer without copying
let ui32 = new Uint32Array(b.buffer, b.byteOffset, b.byteLength / Uint32Array.BYTES_PER_ELEMENT);
Keine Abhängigkeiten, moderate Geschwindigkeit, jede Version von Node.js
Verwenden Sie die Antwort von Martin Thomson, die einfließt An) Zeit. (Siehe auch meine Antworten auf Kommentare zu seiner Antwort zu Nichtoptimierungen. Die Verwendung einer DataView ist langsam. Selbst wenn Sie Bytes umdrehen müssen, gibt es schnellere Möglichkeiten, dies zu tun.)
Abhängigkeit, schnell, Node.js ≤ 0.12 oder iojs 3.x
Sie können verwenden https://www.npmjs.com/package/memcpy um in beide Richtungen zu gehen (Puffer zu ArrayBuffer und zurück). Es ist schneller als die anderen hier geposteten Antworten und eine gut geschriebene Bibliothek. Node 0.12 bis iojs 3.x erfordern ngossens Fork (siehe Das).
-
Es kompiliert nicht erneut node > 0.12
– Pawel Weselow
2. Dezember 2015 um 3:52 Uhr
-
Verwenden Sie ngossens Gabel: github.com/dcodeIO/node-memcpy/pull/6. Siehe auch meine neue Antwort, wenn Sie Knoten 4+ verwenden.
– ZachB
2. Dezember 2015 um 19:09 Uhr
-
Wo waren die
.byteLength
und.byteOffset
dokumentiert?– Константин Ван
23. Januar 2018 um 20:28 Uhr
-
@K._ Diese Eigenschaften werden von TypedArray geerbt: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… und developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
– ZachB
23. Januar 2018 um 20:31 Uhr
-
var ab = b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
hat meinen Tag gerettet– Alexey Sh.
1. Dezember 2018 um 11:54 Uhr
kraag22
“From ArrayBuffer to Buffer” könnte auf diese Weise erfolgen:
var buffer = Buffer.from( new Uint8Array(ab) );
-
Das ist das Gegenteil von dem, was OP wollte.
– Alexander Gontschi
22. April 2016 um 12:33 Uhr
-
Aber das war es, was ich wollte, mein Problem googeln und froh, dass ich die Lösung gefunden habe.
– Maciej Krawczyk
22. März 2017 um 16:04 Uhr
Eine schnellere Art, es zu schreiben
var arrayBuffer = new Uint8Array(nodeBuffer).buffer;
Dies scheint jedoch ungefähr viermal langsamer zu laufen als die vorgeschlagene toArrayBuffer-Funktion auf einem Puffer mit 1024 Elementen.
Константин Ван
1. A Buffer
ist nur ein Ansicht für den Blick in ein ArrayBuffer
.
EIN Buffer
in der Tat ist ein FastBuffer
welcher extends
(erbt von) Uint8Array
die eine Oktetteinheit ist Ansicht („partial accessor“) des eigentlichen Speichers, an ArrayBuffer
.
📜/lib/buffer.js#L65-L73
Node.js 9.4.0
class FastBuffer extends Uint8Array {
constructor(arg1, arg2, arg3) {
super(arg1, arg2, arg3);
}
}
FastBuffer.prototype.constructor = Buffer;
internalBuffer.FastBuffer = FastBuffer;
Buffer.prototype = FastBuffer.prototype;
2. Die Größe eines ArrayBuffer
und die Größe seiner Ansicht variieren.
Grund Nr. 1: Buffer.from(arrayBuffer[, byteOffset[, length]])
.
Mit Buffer.from(arrayBuffer[, byteOffset[, length]])
können Sie eine erstellen Buffer
mit Angabe des Basiswertes ArrayBuffer
und die Position und Größe der Ansicht.
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.
Grund Nr. 2: FastBuffer
Speicherbelegung von .
Es weist den Speicher je nach Größe auf zwei verschiedene Arten zu.
- Wenn die Größe weniger als die Hälfte der Größe von a Gedächtnispool und ist nicht 0 („klein“): es nutzt a Gedächtnispool um den erforderlichen Speicher vorzubereiten.
- Anders: es schafft eine dedizierte
ArrayBuffer
das passt genau zum benötigten Arbeitsspeicher.
📜/lib/buffer.js#L306-L320
Node.js 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
Node.js 9.4.0
function createUnsafeBuffer(size) {
return new FastBuffer(createUnsafeArrayBuffer(size));
}
Was meinst du mit einem „Gedächtnispool?”
EIN Gedächtnispool ist eine feste Größe vorbelegt Speicherblock zum Aufbewahren kleiner Speicherblöcke für Buffer
S. Die Verwendung hält die kleinen Speicherbrocken eng zusammen, verhindert also Zersplitterung verursacht durch getrennte Verwaltung (Zuweisung und Freigabe) von kleinen Speicherblöcken.
In diesem Fall sind die Speicherpools ArrayBuffer
s, deren Größe standardmäßig 8 KiB beträgt, was in angegeben ist Buffer.poolSize
. Wenn es darum geht, einen kleinen Speicherblock für a bereitzustellen Buffer
, es prüft, ob der letzte Speicherpool genügend verfügbaren Speicher hat, um dies zu handhaben; Wenn ja, erstellt es eine Buffer
das “Ansichten” den gegebenen Teil des Speicherpools, ansonsten wird ein neuer Speicherpool erstellt und so weiter.
Sie können auf den Basiswert zugreifen ArrayBuffer
von a Buffer
. Die Buffer
‘S buffer
Eigentum (d.h. geerbt von Uint8Array
) hält es. EIN “klein” Buffer
‘S buffer
Eigentum ist ein ArrayBuffer
die den gesamten Speicherpool darstellt. Also in diesem Fall die ArrayBuffer
und das Buffer
variiert in der Größe.
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.
3. Also müssen wir den Speicher extrahieren „Ansichten.“
Ein ArrayBuffer
hat eine feste Größe, also müssen wir es extrahieren, indem wir eine Kopie des Teils erstellen. Dazu verwenden wir Buffer
‘S byteOffset
Eigentum und length
Eigentumdie vererbt werden Uint8Array
und der ArrayBuffer.prototype.slice
Methodedas eine Kopie eines Teils einer erstellt ArrayBuffer
. Die slice()
-ing-Methode hierin wurde von @ZachB inspiriert.
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
4. Leistungsverbesserung
Wenn Sie die Ergebnisse schreibgeschützt verwenden möchten, oder es in Ordnung ist, die Eingabe zu ändern Buffer
s’ Inhaltkönnen Sie unnötiges Kopieren des Speichers vermeiden.
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
-
Das ist alles schön und gut … aber hast du eigentlich die Frage von OP beantwortet? Wenn ja, ist es begraben…
– Tustin2121
14. Mai 2018 um 16:42 Uhr
-
Gute Antwort! Im
obtain_arraybuffer
:buf.buffer.subarray
scheint nicht zu existieren. Hast du gemeintbuf.buffer.slice
Hier?– Alltagsproduktiv
2. Juli 2018 um 17:41 Uhr
-
@alltagsproduktiv Danke. Wie Sie im Bearbeitungsverlauf sehen können, habe ich tatsächlich verwendet
ArrayBuffer.prototype.slice
und später modifiziert zuUint8Array.prototype.subarray
. Oh, und ich habe es falsch gemacht. Wahrscheinlich war ich damals etwas verwirrt. Dank dir ist jetzt alles gut.– Константин Ван
8. Juli 2018 um 7:18 Uhr
Verwenden Sie das folgende ausgezeichnete npm-Paket: to-arraybuffer
.
Oder Sie können es selbst implementieren. Wenn Ihr Puffer aufgerufen wird buf
mach das:
buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength)
-
Das ist alles schön und gut … aber hast du eigentlich die Frage von OP beantwortet? Wenn ja, ist es begraben…
– Tustin2121
14. Mai 2018 um 16:42 Uhr
-
Gute Antwort! Im
obtain_arraybuffer
:buf.buffer.subarray
scheint nicht zu existieren. Hast du gemeintbuf.buffer.slice
Hier?– Alltagsproduktiv
2. Juli 2018 um 17:41 Uhr
-
@alltagsproduktiv Danke. Wie Sie im Bearbeitungsverlauf sehen können, habe ich tatsächlich verwendet
ArrayBuffer.prototype.slice
und später modifiziert zuUint8Array.prototype.subarray
. Oh, und ich habe es falsch gemacht. Wahrscheinlich war ich damals etwas verwirrt. Dank dir ist jetzt alles gut.– Константин Ван
8. Juli 2018 um 7:18 Uhr
Benny Neugebauer
Sie können an eine denken ArrayBuffer
als getippt Buffer
.
Ein ArrayBuffer
benötigt daher immer einen Typ (den sogenannten “Array Buffer View”). Typischerweise die Array-Pufferansicht hat eine Art Uint8Array
oder Uint16Array
.
Dazu gibt es einen guten Artikel von Renato Mangini Konvertieren zwischen einem ArrayBuffer und einem String.
Die wesentlichen Teile habe ich in einem Codebeispiel (für Node.js) zusammengefasst. Es zeigt auch, wie man zwischen den eingegebenen konvertiert ArrayBuffer
und die untypisierten 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!"
Mich würde interessieren warum man das machen muss?
– Chris Biscardi
23. Dezember 2011 um 2:46 Uhr
Ein gutes Beispiel wäre das Schreiben einer Bibliothek, die mit Dateien in Browsern und auch für NodeJS-Dateien funktioniert?
– fbstj
18. Januar 2012 um 18:36 Uhr
oder mit einer Browserbibliothek in NodeJS
– Orangenhund
20. Juni 2013 um 15:43 Uhr
Ein weiterer Grund ist, dass ein Float zu viele Bytes RAM benötigt, wenn es in einem gespeichert wird
Array
. Um also viele Schwimmer zu speichern, die Sie benötigenFloat32Array
wo es 4 Bytes dauert. Und wenn Sie diese Floats schnell in eine Datei serialisieren möchten, benötigen Sie eineBuffer
da die Serialisierung zu JSON Ewigkeiten dauert.– nponeccop
13. November 2013 um 13:32 Uhr
const file = fs.readFileSync(filePath);
also wie benutze ich das? … 30 Minuten später, wow, ich vermisse C.– Wilhelm Entriken
27. Mai 2020 um 4:02 Uhr