web-dev-qa-db-fra.com

Comment écrire un fichier depuis un ArrayBuffer dans JS

J'essaie d'écrire un programme de téléchargement de fichiers pour Framework Meteor . Le principe consiste à séparer le fichier client du serveur ArrayBuffer en petits paquets de 4096 bits envoyés au serveur par le biais d'un logiciel Meteor.method.

Le code simplifié ci-dessous est la partie du client qui envoie un bloc au serveur. Il est répété jusqu'à ce que offset atteigne data.byteLength :

// data is an ArrayBuffer
var total = data.byteLength;
var offset = 0;

var upload = function() {
  var length = 4096; // chunk size

  // adjust the last chunk size
  if (offset + length > total) {
     length = total - offset;
  }

  // I am using Uint8Array to create the chunk
  // because it can be passed to the Meteor.method natively
  var chunk = new Uint8Array(data, offset, length);

  if (offset < total) {
     // Send the chunk to the server and tell it what file to append to
     Meteor.call('uploadFileData', fileId, chunk, function (err, length) {
        if (!err) {
          offset += length;
          upload();
        }
     }
  }
};
upload(); // start uploading

Le code simplifié ci-dessous est la partie du serveur qui reçoit le bloc et l'écrit dans le système de fichiers:

var fs = Npm.require('fs');
var Future = Npm.require('fibers/future');

Meteor.methods({
  uploadFileData: function(fileId, chunk) {
    var fut = new Future();
    var path = '/uploads/' + fileId;

    // I tried that with no success
    chunk = String.fromCharCode.apply(null, chunk);

    // how to write the chunk that is an Uint8Array to the disk ?
    fs.appendFile(path, chunk, 'binary', function (err) {
      if (err) {
        fut.throw(err);
      } else {
        fut.return(chunk.length);
      }
    });
    return fut.wait();
  }
});

J'ai échoué à écrire un fichier valide sur le disque. En fait, le fichier est enregistré mais je ne peux pas l'ouvrir. Lorsque je vois le contenu dans un éditeur de texte, il ressemble au fichier d'origine (un jpg par exemple), mais certains caractères sont différents. , Je pense que cela pourrait être un problème d’encodage car la taille du fichier n’est pas la même, mais je ne sais pas comment résoudre ce problème ...

13
Karl.S

Enregistrer le fichier était aussi simple que de créer un nouveau tampon avec l'objet Uint8Array:

// chunk is the Uint8Array object
fs.appendFile(path, new Buffer(chunk), function (err) {
    if (err) {
      fut.throw(err);
    } else {
      fut.return(chunk.length);
    }
});
16
Karl.S

S'appuyant sur Karl.S answer , cela a fonctionné pour moi, en dehors de tout cadre:

fs.appendFileSync(outfile, new Buffer(arrayBuffer));
6
toms

Je voulais juste ajouter que dans Meteor plus récent, vous pourriez éviter un enfer de rappel avec async/await. Await lancera également et transmettra l'erreur au client

Meteor.methods({
  uploadFileData: async function(file_id, chunk) {
    var path = 'somepath/' + file_id; // be careful with this, make sure to sanitize file_id
    await fs.appendFile(path, new Buffer(chunk));
    return chunk.length;
  }
});
1
Alex K