web-dev-qa-db-de.com

So schreiben Sie eine Datei aus einem ArrayBuffer in JS

Ich versuche, einen Datei-Uploader für das Meteor-Framework zu schreiben. Das Prinzip besteht darin, die Datei auf dem Client von einem ArrayBuffer in kleine Pakete von 4096 Bits aufzuteilen, die über eine Meteor-Methode an den Server gesendet werden.

Der vereinfachte -Code unten ist der Teil des Clients, der einen Block an den Server sendet. Er wird wiederholt, bis offset erreicht 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

Der vereinfachte -Code unten ist der Teil auf dem Server, der den Block empfängt und in das Dateisystem schreibt:

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();
  }
});

Ich habe keine gültige Datei auf die Festplatte geschrieben. Die Datei wird zwar gespeichert, aber ich kann sie nicht öffnen. Wenn ich den Inhalt in einem Texteditor sehe, ähnelt er der Originaldatei (z. B. ein JPG), einige Zeichen unterscheiden sich jedoch Ich denke, das könnte ein Codierungsproblem sein, da die Dateigröße nicht gleich ist, aber ich weiß nicht, wie ich das beheben kann ...

13
Karl.S

Das Speichern der Datei war so einfach wie das Erstellen eines neuen Puffers mit dem Uint8Array-Objekt:

// 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

Aufbauend auf Karl.S answer , das funktionierte für mich auch ohne Rahmen

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

Ich wollte nur hinzufügen, dass Sie in neuerem Meteor mit async/await eine Callback-Hölle vermeiden können. Await wird auch den Fehler werfen und an den Client weiterleiten

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