107 votes

Comment ajouter des données binaires à un tampon dans node.js

J'ai un tampon avec des données binaires :

var b = new Buffer ([0x00, 0x01, 0x02]);

et je veux ajouter 0x03.

Comment puis-je ajouter plus de données binaires ? Je recherche dans la documentation mais pour ajouter des données, cela doit être une chaîne de caractères, sinon une erreur se produit (TypeError: Argument must be a string) :

var b = new Buffer (256);
b.write ("hola");
console.log (b.toString ("utf8", 0, 4)); //hola
b.write (", adios", 4);
console.log (b.toString ("utf8", 0, 11)); //hola, adios

Donc, la seule solution que je vois ici est de créer un nouveau tampon pour chaque donnée binaire ajoutée et de le copier dans le tampon principal avec le décalage correct :

var b = new Buffer (4); //4 pour avoir un tampon joliment imprimé, mais la taille sera de 16 Ko
new Buffer ([0x00, 0x01, 0x02]).copy (b);
console.log (b); //
new Buffer ([0x03]).copy (b, 3);
console.log (b); //

Mais cela semble un peu inefficace car je dois instancier un nouveau tampon pour chaque ajout.

Connaissez-vous un meilleur moyen d'ajouter des données binaires ?

MODIFIER

J'ai écrit un BufferedWriter qui écrit des octets dans un fichier en utilisant des tampons internes. Similaire à BufferedReader mais pour l'écriture.

Un exemple rapide :

//Le BufferedWriter tronque le fichier car append == false
new BufferedWriter ("file")
    .on ("error", function (error){
        console.log (error);
    })

    //Depuis le début du fichier :
    .write ([0x00, 0x01, 0x02], 0, 3) //Écrit 0x00, 0x01, 0x02
    .write (new Buffer ([0x03, 0x04]), 1, 1) //Écrit 0x04
    .write (0x05) //Écrit 0x05
    .close (); //Ferme l'écrivain. Un flush est implicitement effectué.

//Le BufferedWriter ajoute du contenu à la fin du fichier car append == true
new BufferedWriter ("file", true)
    .on ("error", function (error){
        console.log (error);
    })

    //Depuis la fin du fichier :
    .write (0xFF) //Écrit 0xFF
    .close (); //Ferme l'écrivain. Un flush est implicitement effectué.

//Le fichier contient : 0x00, 0x01, 0x02, 0x04, 0x05, 0xFF

DERNIERE MISE A JOUR

Utilisez concat.

182voto

Brad Points 61171

Réponse mise à jour pour Node.js ~>0.8

Node est capable de concaténer des buffers par lui-même maintenant.

var newBuffer = Buffer.concat([buffer1, buffer2]);

Ancienne réponse pour Node.js ~0.6

J'utilise un module pour ajouter une fonction .concat, entre autres :

https://github.com/coolaj86/node-bufferjs

Je sais que ce n'est pas une solution "pure", mais cela fonctionne très bien pour mes besoins.

12voto

stewe Points 14623

Les tampons ont toujours une taille fixe, il n'y a pas de moyen intégré pour les redimensionner dynamiquement, donc votre approche de les copier dans un tampon plus grand est la seule solution.

Cependant, pour être plus efficace, vous pourriez rendre le tampon plus grand que le contenu d'origine, de sorte qu'il contienne un peu d'espace "libre" où vous pouvez ajouter des données sans réallouer le tampon. De cette façon, vous n'avez pas besoin de créer un nouveau tampon et de copier le contenu à chaque opération d'ajout.

10voto

kmcguire Points 116

Ceci est pour aider toute personne qui vient ici à la recherche d'une solution et qui souhaite une approche pure. Je recommanderais de comprendre ce problème car il peut se produire dans de nombreux endroits différents, pas seulement avec un objet JS Buffer. En comprenant pourquoi le problème existe et comment le résoudre, vous améliorerez votre capacité à résoudre d'autres problèmes à l'avenir, car celui-ci est si fondamental.

Pour ceux d'entre nous qui doivent traiter ces problèmes dans d'autres langues, il est assez naturel de concevoir une solution, mais il y a des gens qui peuvent ne pas réaliser comment abstraire les complexités et mettre en œuvre un tampon dynamique efficace en général. Le code ci-dessous pourrait potentiellement être optimisé davantage.

J'ai laissé la méthode de lecture non implémentée pour garder l'exemple de petite taille.

La fonction realloc en C (ou dans n'importe quel langage traitant des allocations intrinsèques) ne garantit pas que l'allocation sera étendue en taille sans déplacer les données existantes - bien que parfois cela soit possible. Par conséquent, la plupart des applications qui ont besoin de stocker une quantité inconnue de données utiliseront une méthode comme celle-ci et ne se réalloueront pas constamment, sauf si la réaffectation est très peu fréquente. C'est essentiellement ainsi que la plupart des systèmes de fichiers gèrent l'écriture de données dans un fichier. Le système de fichiers alloue simplement un autre nœud et garde tous les nœuds liés ensemble, et lorsque vous lisez à partir de celui-ci, la complexité est abstraite de manière à ce que le fichier/tampon semble être un tampon continu unique.

Pour ceux d'entre vous qui souhaitent comprendre la difficulté de simplement fournir un tampon dynamique à haute performance, vous n'avez qu'à consulter le code ci-dessous et faire des recherches sur les algorithmes de tas de mémoire et sur le fonctionnement du tas de mémoire pour les programmes.

La plupart des langues fourniront un tampon de taille fixe pour des raisons de performance, puis offriront une autre version de taille dynamique. Certains systèmes de langage optent pour un système de tiers où ils maintiennent la fonctionnalité de base minimale (distribution de base) et encouragent les développeurs à créer des bibliothèques pour résoudre des problèmes supplémentaires ou de plus haut niveau. C'est pourquoi vous pouvez vous demander pourquoi un langage ne fournit pas certaines fonctionnalités. Cette petite fonctionnalité de base permet de réduire les coûts de maintenance et d'amélioration du langage, mais vous finissez par devoir écrire vos propres implémentations ou dépendre d'un tiers.

var Buffer_A1 = function (taille_chunk) {
    this.buffer_list = [];
    this.total_size = 0;
    this.cur_size = 0;
    this.cur_buffer = [];
    this.chunk_size = chunk_size || 4096;

    this.buffer_list.push(new Buffer(this.chunk_size));
};

Buffer_A1.prototype.writeByteArrayLimited = function (data, offset, length) {
    var can_write = length > (this.chunk_size - this.cur_size) ? (this.chunk_size - this.cur_size) : length;

    var lastbuf = this.buffer_list.length - 1;

    for (var x = 0; x < can_write; ++x) {
        this.buffer_list[lastbuf][this.cur_size + x] = data[x + offset];
    }

    this.cur_size += can_write;
    this.total_size += can_write;

    if (this.cur_size == this.chunk_size) {
        this.buffer_list.push(new Buffer(this.chunk_size));
        this.cur_size = 0;
    }

    return can_write;
};

/*
    Le paramètre `data` peut être tout élément ressemblant à un tableau. Il doit simplement
    supporter l'indexation et une longueur et produire une valeur acceptable pour être
    utilisée avec Buffer.
*/
Buffer_A1.prototype.writeByteArray = function (data, offset, length) {
    offset = offset == undefined ? 0 : offset;
    length = length == undefined ? data.length : length;

    var rem = longueur;
    while (rem > 0) {
        rem -= this.writeByteArrayLimited(data, longueur - rem, rem);
    }
};

Buffer_A1.prototype.readByteArray = function (data, offset, length) {
    /*
        Si vous vouliez vraiment implémenter une certaine fonction de lecture
        alors vous auriez à traiter des lectures non alignées qui pourraient
        couvrir deux tampons.
    */
};

Buffer_A1.prototype.getSingleBuffer = function () {
    var obuf = new Buffer(this.total_size);
    var cur_off = 0;
    var x;

    for (x = 0; x < this.buffer_list.length - 1; ++x) {
        this.buffer_list[x].copy(obuf, cur_off);
        cur_off += this.buffer_list[x].length;
    }

    this.buffer_list[x].copy(obuf, cur_off, 0, this.cur_size);

    return obuf;
};

-1voto

Havrylov Anton Points 1

Insérer un byte à un endroit spécifique.

insertToArray(arr, index, item) {
   return Buffer.concat([arr.slice(0, index), Buffer.from(item, "utf-8"), arr.slice(index)]);
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X