2015-06-02 13 views
6

Dal nodo docs sulla creazione di array tipizzati da buffer: memoriaCreazione di un array tipizzato da una matrice di byte memorizzato come nodo Buffer

del tampone viene interpretato come una matrice, non una matrice di byte. Che è , new Uint32Array(new Buffer([1,2,3,4])) crea un elemento 4 Uint32Array con elementi [1,2,3,4], non un Uint32Array con un unico elemento [0x1020304] o [0x4030201].

Ciò contrasta a JavaScript pianura, dove si crea una vista matrice tipizzata da un'ArrayBuffer utilizza la memoria del ArrayBuffer come byte (come un reinterpret_cast in C++). Ho bisogno di questo comportamento nel nodo quando si opera su Buffer di nodo.

Potrei convertire il buffer in un ArrayBuffer, ma questo è troppo lento per la mia applicazione. (Ho provato molti metodi - ma sono tutti O (n).) (Modifica: il metodo più veloce che ho trovato è this, che è un singolo memmove op e abbastanza veloce, ma ha ancora almeno un momentaneo 2x consumo di memoria fino al rilascio del riferimento al buffer originale.

C'è un modo (veloce/O (1) per ottenere un array tipizzato da un buffer, utilizzando il contenuto del buffer come byte anziché elementi? (La dimensione dell'elemento dell'array tipizzato richiesto è> 1 byte, manco a dirlo.)

+0

Che tipo di operazione deve fare con l'array? Se è di sola lettura, allora perché non fare riferimento agli elementi nel buffer direttamente attraverso l'offset? Es .: 'buf.readUInt32LE (i * 4)' dove 'i' è l'indice dell'array? –

+0

Ho bisogno di scorrere l'array rapidamente e ripetutamente. I metodi 'read *' sono molto lenti. – ZachB

+0

Penso che non ci sia posto più rapidamente: se abbiamo bisogno di un valore Int32 dell'indice 'i':' var k = i * 4; return buf [k] | buf [k + 1] << 8 | buf [k + 2] << 16 | buf [k + 3] << 256; ' –

risposta

2

Per quanto ne so, non è possibile farlo senza fare una copia dei dati in memoria. Anche l'esempio new Uint32Array(new Buffer([1,2,3,4])) esegue internamente questo (ovvero non è O (1)).

Nota che digitato le matrici sono solo vista di un ArrayBuffer (non Buffer, questo non è possibile). new Uint32Array(array) crea un ArrayBuffer di 4 * array.length byte. Puoi accedervi con uint32Array.buffer. Il costruttore considera il tuo Buffer diverso da un normale Array.

La soluzione migliore che conosco è the one you already found.

Un altro problema con l'utilizzo di Uint32Array per quello che si tenta di fare è che è depends on platform byte order. È possibile eseguire iterazioni su Buffer come this o utilizzare DataView se si desidera essere sicuri.

2

A partire dal nodo 4.0, buffer sono Uint8Arrays e nuovi punti di vista può essere costruito su di loro direttamente:

var b = new Buffer([1,2,3,4]); 
new Uint32Array(b.buffer, b.byteOffset); 

Questo mini-esempio presuppone che b è maggiore di ~ 4096 (la soglia per un buffer possedere una propria pezzo di memoria contro la condivisione di un pezzo più grande). Vedere Convert a binary NodeJS Buffer to JavaScript ArrayBuffer per maggiori informazioni - in genere è necessario chiamare b.slice() per operare solo sulla memoria che si possiede.

+0

NB: 'nuovo Uint32Array (b.buffer, b.byteOffset) .length' ->' 2046' ... non funziona. Hai ragione - può essere costruito direttamente, ma "come uint8array" non è un byte. – shaunc

+0

@shaunc funziona, guarda il contenuto del risultato. La lunghezza imprevista è un effetto collaterale dell'amplificatore di buffer di array condiviso del nodo. Usa 'b.slice' almeno quando il buffer è piccolo o sempre sicuro. – ZachB

+0

'new Uint32Array (b.buffer, b.byteOffset) .slice (0,4)' -> 'Uint32Array [67305985, 0, 8192, 0]'? lo stesso quando riscrivo entrambi "b" come 'b.slice (0,4)'? (NB: nodo 9.3.0) OOPS ... Credo che sia giusto :) Grumble ... non mi permetterà di correggere il mio errore con upvote fino a che non modifichi - qualsiasi modifica lo farà e avrò l'upvot. Scusa – shaunc

Problemi correlati