web-dev-qa-db-fra.com

Convertir un tampon binaire NodeJS en JavaScript ArrayBuffer

Comment convertir un tampon binaire NodeJS en JavaScript ArrayBuffer?

96
Drake Amara

Les instances de Buffer sont également des instances de Uint8Array dans node.js 4.x et versions ultérieures. Ainsi, la solution la plus efficace consiste à accéder directement à la propriété buf.buffer, conformément à https://stackoverflow.com/a/31394257/1375574 . Le constructeur Buffer prend également un argument ArrayBufferView si vous devez aller dans l'autre sens.

Notez que cela ne créera pas de copie, ce qui signifie que les écritures sur n'importe quel ArrayBufferView seront écrites sur l'instance de tampon d'origine.


Dans les versions plus anciennes, node.js inclut ArrayBuffer dans la v8, mais la classe Buffer fournit une API plus flexible. Pour lire ou écrire sur un ArrayBuffer, il vous suffit de créer une vue et de la copier.

De 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;
}

De 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;
}
91
Martin Thomson
  • Pas de dépendances, le plus rapide, noeud 4.x et supérieur

Les tampons sont des Uint8Arrays, il vous suffit donc d'accéder à son ArrayBuffer. C'est 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);

Les options slice et offset sont required car les petits tampons (<4096 octets, je pense) sont des vues sur un ArrayBuffer partagé. Sans cela, vous pourriez vous retrouver avec un ArrayBuffer contenant des données d'un autre TypedArray.

  • Aucune dépendance, vitesse modérée, version de noeud quelconque

Utilisez la réponse de Martin Thomson , qui s'exécute dans le temps O(n). (Voir également mes réponses aux commentaires sur sa réponse concernant les non-optimisations. L'utilisation d'un DataView est lente. Même si vous devez retourner des octets, il existe des moyens plus rapides pour le faire.)

  • Dependency, fast, toute version de node

Vous pouvez utiliser https://www.npmjs.com/package/memcpy pour aller dans un sens ou dans l'autre (mémoire tampon vers ArrayBuffer et retour). C'est plus rapide que les autres réponses affichées ici et c'est une bibliothèque bien écrite. Les nœuds 0.12 à iojs 3.x nécessitent la fourchette de ngossen (voir this ).

46
ZachB

"De ArrayBuffer à Buffer" pourrait être fait de cette façon: 

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

Un moyen plus rapide de l'écrire

var arrayBuffer = new Uint8Array(nodeBuffer).buffer;

Cependant, cela semble être environ 4 fois plus lent que la fonction suggérée toArrayBuffer sur un tampon de 1024 éléments.

23
David Fooks

Utilisez l'excellent paquet npm suivant: to-arraybuffer .

Ou, vous pouvez l'implémenter vous-même. Si votre tampon s'appelle buf, procédez comme suit:

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

Vous pouvez imaginer une ArrayBuffer comme une Buffer dactylographiée. 

Une ArrayBuffer a donc toujours besoin d'un type (appelé "Array Buffer View"). Généralement, la vue Array Buffer View a le type Uint8Array ou Uint16Array.

Il y a un bon article de Renato Mangini sur la conversion entre un ArrayBuffer et un String .

J'ai résumé les parties essentielles dans un exemple de code (pour Node.js). Il montre également comment convertir une ArrayBuffer typée et une Buffer non typée.

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
Benny Neugebauer

J'ai essayé ce qui précède pour un Float64Array et cela n'a tout simplement pas fonctionné.

J'ai fini par me rendre compte que les données devaient être lues «dans la vue» par tranches correctes. Cela signifie lire 8 octets à la fois à partir du tampon source.

Quoi qu'il en soit, c'est ce que j'ai fini par ...

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

Ce proxy exposera le tampon sous la forme de n'importe lequel des TypedArrays, sans aucune copie. : 

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

Cela ne fonctionne que sur LE, mais peut être facilement porté sur BE . En outre, jamais eu à tester l'efficacité de cela.

0
Dlabz