nodejs node new length example create javascript node.js binary buffer arraybuffer

new - Convierta un búfer NodeJS binario en ArrayBuffer de JavaScript



nodejs base64 encode (11)

¿Cómo puedo convertir un búfer binario NodeJS en un ArrayBuffer de JavaScript?


1. Un Buffer es solo una vista para mirar en un ArrayBuffer .

Un Buffer , de hecho, es un FastBuffer , que se extends (hereda de) Uint8Array , que es una vista de unidad de octetos ("acceso parcial") de la memoria real, un ArrayBuffer .

L /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. El tamaño de un ArrayBuffer y el tamaño de su vista pueden variar.

Motivo n. ° 1: Buffer.from(arrayBuffer[, byteOffset[, length]]) .

Con Buffer.from(arrayBuffer[, byteOffset[, length]]) , puede crear un Buffer especificando su ArrayBuffer subyacente y la posición y el tamaño de la vista.

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.

Razón # 2: asignación de memoria de FastBuffer .

Asigna la memoria de dos formas diferentes según el tamaño.

  • Si el tamaño es menor que la mitad del tamaño de un grupo de memoria y no es 0 ("pequeño") : utiliza un grupo de memoria para preparar la memoria requerida.
  • De lo contrario : crea un ArrayBuffer dedicado que se ajusta exactamente a la memoria requerida.
L /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); } } L /lib/buffer.js#L98-L100 Node.js 9.4.0

function createUnsafeBuffer(size) { return new FastBuffer(createUnsafeArrayBuffer(size)); }

¿Qué quiere decir con un " grupo de memoria "?

Un grupo de memoria es un bloque de memoria preasignado de tamaño fijo para mantener trozos de memoria de tamaño pequeño para los Buffer . Su uso mantiene los trozos de memoria de pequeño tamaño bien juntos, por lo que evita la fragmentation causada por la administración por separado (asignación y desasignación) de trozos de memoria de pequeño tamaño.

En este caso, los grupos de memoria son ArrayBuffer s cuyo tamaño es 8 KiB por defecto, que se especifica en Buffer.poolSize . Cuando se trata de proporcionar un fragmento de memoria de pequeño tamaño para un Buffer , verifica si el último grupo de memoria tiene suficiente memoria disponible para manejar esto; si es así, crea un Buffer que "visualiza" el fragmento parcial dado del grupo de memoria, de lo contrario, crea un nuevo grupo de memoria, etc.

Puede acceder al ArrayBuffer subyacente de un Buffer . La propiedad de buffer del buffer (es decir, heredada de Uint8Array ) lo tiene. Una propiedad de buffer "pequeña" del Buffer es un ArrayBuffer que representa todo el grupo de memoria. Entonces, en este caso, el ArrayBuffer y el Buffer varían de tamaño.

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. Entonces necesitamos extraer la memoria que "ve" .

Un ArrayBuffer se fija en tamaño, por lo que debemos extraerlo haciendo una copia de la pieza. Para hacer esto, utilizamos la developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Buffer y la developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… length , que se heredan de Uint8Array , y el método ArrayBuffer.prototype.slice , que hace una copia de una parte de un ArrayBuffer . El método de @ZachB slice() está inspirado en @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

4. Mejora del rendimiento

Si va a utilizar los resultados como de solo lectura, o está bien modificar los contenidos del Buffer entrada , puede evitar copias de memoria innecesarias.

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.buffer.subarray(buf.byteOffset, buf.byteOffset + 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


"De ArrayBuffer a Buffer" podría hacerse de esta manera:

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



Intenté lo anterior para un Float64Array y simplemente no funcionó.

Terminé dándome cuenta de que realmente los datos debían leerse ''INTO'' en la vista en los fragmentos correctos. Esto significa leer 8 bytes a la vez del Buffer fuente.

De todos modos, esto es con lo que terminé ...

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


NodeJS, en un punto (creo que era v0.6.x), tenía compatibilidad con ArrayBuffer. Creé una pequeña biblioteca para codificación y decodificación base64 here , pero desde la actualización a v0.7, las pruebas (en NodeJS) fallan. Estoy pensando en crear algo que normalice esto, pero hasta entonces, supongo que se debe usar el Buffer nativo de Node.


Puedes pensar en un ArrayBuffer como un Buffer tipeado.

ArrayBuffer tanto, un ArrayBuffer siempre necesita un tipo (la llamada "Vista de Buffer de Array"). Por lo general, la vista Buffer Buffer tiene un tipo de Uint8Array o Uint16Array .

Hay un buen artículo de Renato Mangini sobre la conversión entre un ArrayBuffer y un String .

He resumido las partes esenciales en un ejemplo de código (para Node.js). También muestra cómo convertir entre el ArrayBuffer tipeado y el Buffer tipo.

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!"


Una forma más rápida de escribirlo

var arrayBuffer = new Uint8Array(nodeBuffer).buffer;

Sin embargo, esto parece ejecutarse aproximadamente 4 veces más lento que la función sugerida para ArrayBuffer en un búfer con 1024 elementos.


Use el siguiente paquete excelente npm: to-arraybuffer .

O bien, puede implementarlo usted mismo. Si su memoria intermedia se llama buf , haga esto:

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


Ya actualicé mi nodo a la Versión 5.0.0 Y trabajo con esto:

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 }

Lo uso para verificar la imagen de mi disco vhd.


Las instancias de Buffer también son instancias de Uint8Array en node.js 4.xy superiores. Por lo tanto, la solución más eficiente es acceder a la propiedad buf.buffer directamente, según https://.com/a/31394257/1375574 . El constructor Buffer también toma un argumento ArrayBufferView si necesita ir en la otra dirección.

Tenga en cuenta que esto no creará una copia, lo que significa que las escrituras en cualquier ArrayBufferView se escribirán en la instancia original de Buffer.

En versiones anteriores, node.js tiene ArrayBuffer como parte de v8, pero la clase Buffer proporciona una API más flexible. Para leer o escribir en un ArrayBuffer, solo necesita crear una vista y copiarla.

De Buffer a 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 a Buffer:

function toBuffer(ab) { var buf = new Buffer(ab.byteLength); var view = new Uint8Array(ab); for (var i = 0; i < buf.length; ++i) { buf[i] = view[i]; } return buf; }


  • Sin dependencias, más rápido, nodo 4.xy posterior

Los búferes son Uint8Arrays, por lo que solo necesita acceder a su ArrayBuffer. Esto es 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);

La slice y el desplazamiento son necesarios porque los pequeños búferes (<4096 bytes, creo) son vistas en un ArrayBuffer compartido. Sin él, podrías terminar con un ArrayBuffer que contiene datos de otro TypedArray.

  • Sin dependencias, velocidad moderada, ninguna versión de nodo

Use la respuesta de Martin Thomson , que se ejecuta en O (n) tiempo. (Consulte también mis respuestas a los comentarios sobre su respuesta sobre las no optimizaciones. Usar DataView es lento. Incluso si necesita voltear los bytes, existen formas más rápidas de hacerlo).

  • Dependencia, rápido, cualquier versión de nodo

Puede usar https://www.npmjs.com/package/memcpy para ir en cualquier dirección (Buffer a ArrayBuffer y viceversa). Es más rápido que las otras respuestas publicadas aquí y es una biblioteca bien escrita. El nodo 0.12 a iojs 3.x requiere la horquilla de ngossen (ver this ).