Recherche…


Remarques

Le package CollectionFS a été mis en attente et abandonné par son auteur; cependant, comme il n'y a pas d'autre package dans Atmosphere ou l'écosystème Meteor pour utiliser la fonctionnalité GridFS de Mongo, et que le code fonctionne toujours parfaitement bien; Nous vous recommandons de ne pas supprimer l'exemple de la documentation StackOverflow tant qu'une autre solution GridFS ne peut pas être documentée pour son remplacement.

Recherche supplémentaire
Téléchargements de Filepicker.io et conversion d'image
Fichier de sauvegarde de Dario
Modèle de téléchargement de fichiers de Micha Roon
Package de téléchargement de fichier EventedMind

Serveur / Client

Le téléchargement de fichiers peut être facile ou très compliqué, selon ce que vous voulez faire. En général, transférer un fichier n'est pas si difficile. Mais il y a beaucoup de cas limites autour des pièces jointes, des fichiers binaires, etc. Et le véritable point d'ancrage est la mise à l'échelle horizontale et la création d'une solution qui fonctionne lorsque le serveur est cloné une seconde, troisième et nième fois.

Commençons par un modèle de téléchargement serveur / client de base. Nous commençons par ajouter un élément d'entrée de fichier au modèle d'objet du document.

<template name="example">
  <input type=file />
</template>

Ensuite, attachez un événement à l'élément d'entrée de votre contrôleur et appelez une méthode Meteor locale «startFileTransfer» pour lancer le transfert.

// client/example.js
Template.example.events({
  'change input': function(ev) {  
    _.each(ev.srcElement.files, function(file) {
      Meteor.startFileTransfer(file, file.name);
    });
  }
});

// client/save.js
/**
 * @blob (https://developer.mozilla.org/en-US/docs/DOM/Blob)
 * @name the file's name
 * @type the file's type: binary, text (https://developer.mozilla.org/en-US/docs/DOM/FileReader#Methods) 
 *
 * TODO Support other encodings: https://developer.mozilla.org/en-US/docs/DOM/FileReader#Methods
 * ArrayBuffer / DataURL (base64)
 */
Meteor.startFileTransfer = function(blob, name, path, type, callback) {
  var fileReader = new FileReader(),
    method, encoding = 'binary', type = type || 'binary';
  switch (type) {
    case 'text':
      // TODO Is this needed? If we're uploading content from file, yes, but if it's from an input/textarea I think not...
      method = 'readAsText';
      encoding = 'utf8';
      break;
    case 'binary': 
      method = 'readAsBinaryString';
      encoding = 'binary';
      break;
    default:
      method = 'readAsBinaryString';
      encoding = 'binary';
      break;
  }
  fileReader.onload = function(file) {
    Meteor.call('saveFileToDisk', file.srcElement.result, name, path, encoding, callback);
  }
  fileReader[method](blob);
}

Le client appelle alors la méthode du serveur saveFileToDisk, qui effectue le transfert proprement dit et met tout sur le disque.

// 
/**
 * TODO support other encodings:
 * http://stackoverflow.com/questions/7329128/how-to-write-binary-data-to-a-file-using-node-js
 */
Meteor.methods({
  saveFileToDisk: function(blob, name, path, encoding) {
    var path = cleanPath(path), fs = __meteor_bootstrap__.require('fs'),
      name = cleanName(name || 'file'), encoding = encoding || 'binary',
      chroot = Meteor.chroot || 'public';
    // Clean up the path. Remove any initial and final '/' -we prefix them-,
    // any sort of attempt to go to the parent directory '..' and any empty directories in
    // between '/////' - which may happen after removing '..'
    path = chroot + (path ? '/' + path + '/' : '/');

    // TODO Add file existance checks, etc...
    fs.writeFile(path + name, blob, encoding, function(err) {
      if (err) {
        throw (new Meteor.Error(500, 'Failed to save file.', err));
      } else {
        console.log('The file ' + name + ' (' + encoding + ') was saved to ' + path);
      }
    }); 

    function cleanPath(str) {
      if (str) {
        return str.replace(/\.\./g,'').replace(/\/+/g,'').
          replace(/^\/+/,'').replace(/\/+$/,'');
      }
    }
    function cleanName(str) {
      return str.replace(/\.\./g,'').replace(/\//g,'');
    }
  }
});

C'est en quelque sorte l'approche la plus simple et cela laisse beaucoup à désirer. C'est peut-être bien pour télécharger un fichier CSV ou quelque chose, mais c'est à peu près tout.

Dropzone (avec fer: routeur)

Si nous voulons quelque chose d'un peu plus raffiné, avec une interface utilisateur Dropzone intégrée et un point de terminaison REST, nous devrons commencer à ajouter des itinéraires et des packages REST personnalisés avec des assistants d'interface utilisateur.

Commençons par importer Iron Router et Dropzone.

 meteor add iron:router
 meteor add awatson1978:dropzone

Et configurez la route URL de téléchargement qui est spécifiée dans l'aide de dropzone.

Router.map(function () {
    this.route('uploads', {
      where: 'server',
      action: function () {
        var fs = Npm.require('fs');
        var path = Npm.require('path');
        var self = this;

        ROOT_APP_PATH = fs.realpathSync('.');

        // dropzone.js stores the uploaded file in the /tmp directory, which we access
        fs.readFile(self.request.files.file.path, function (err, data) {

          // and then write the file to the uploads directory
          fs.writeFile(ROOT_APP_PATH + "/assets/app/uploads/" +self.request.files.file.name, data, 'binary', function (error, result) {
            if(error){
              console.error(error);
            }
            if(result){
              console.log('Success! ', result);
            }
          });
        });
      }
    });
  });

Cool! Nous avons un téléchargeur de fichiers avec une interface utilisateur snazzy et un point de terminaison REST programmable. Malheureusement, cela ne s'adapte pas particulièrement bien.

Filepicker.io

Pour faire évoluer les choses, nous devons cesser d'utiliser le stockage local sur notre serveur et commencer à utiliser un service de stockage de fichiers dédié ou à mettre en œuvre une couche de stockage horizontale. La manière la plus simple de commencer avec le stockage de fichiers évolutif consiste à utiliser une solution telle que Filepicker.io, qui prend en charge S3, Azure, Rackspace et Dropbox. loadpicker a été un unipackage populaire de Filerpicker pendant un certain temps.

meteor add mrt:filepicker

Le modèle Filepicker est assez différent des autres solutions, car il s’agit en réalité d’une intégration tierce. Commencez par ajouter une entrée de filtre de fichiers, que vous verrez fortement en fonction des attributs data- *, ce qui est un modèle assez rare dans les applications Meteor.

<input type="filepicker"
  id="filepickerAttachment"
  data-fp-button-class="btn filepickerAttachment"
  data-fp-button-text="Add image" 
  data-fp-mimetypes="image/*"
  data-fp-container="modal"
  data-fp-maxsize="5000000" 
  data-fp-services="COMPUTER,IMAGE_SEARCH,URL,DROPBOX,GITHUB,GOOGLE_DRIVE,GMAIL">

Vous devrez également définir une clé API, créer le widget Filepicker, le déclencher et observer ses sorties.

if(Meteor.isClient){
  Meteor.startup(function() {
    filepicker.setKey("YourFilepickerApiKey");
  });
  Template.yourTemplate.rendered = function(){
    filepicker.constructWidget($("#filepickerAttachment"));
  }
  Template.yourTemplate.events({
  'change #filepickerAttachment': function (evt) {
    console.log("Event: ", evt, evt.fpfile, "Generated image url:", evt.fpfile.url);
  });
});

CollectionFS

Cependant, si vous êtes vraiment sérieux en matière de stockage et que vous souhaitez stocker des millions d'images, vous devez exploiter l'infrastructure GridFS de Mongo et créer vous-même une couche de stockage. Pour cela, vous aurez besoin de l'excellent sous-système CollectionFS.

Commencez par ajouter les paquets nécessaires.

meteor add cfs:standard-packages
meteor add cfs:filesystem

Et ajouter un élément de téléchargement de fichier à votre modèle d'objet.

<template name="yourTemplate">
    <input class="your-upload-class" type="file">
</template>

Ajoutez ensuite un contrôleur d'événements sur le client.

Template.yourTemplate.events({
    'change .your-upload-class': function(event, template) {
        FS.Utility.eachFile(event, function(file) {
            var yourFile = new FS.File(file);
            yourFile.creatorId = Meteor.userId(); // add custom data
            YourFileCollection.insert(yourFile, function (err, fileObj) {
                if (!err) {
                   // do callback stuff
                }
            });
        });
    }
});

Et définissez vos collections sur votre serveur:

YourFileCollection = new FS.Collection("yourFileCollection", {
    stores: [new FS.Store.FileSystem("yourFileCollection", {path: "~/meteor_uploads"})]
});
YourFileCollection.allow({
    insert: function (userId, doc) {
        return !!userId;
    },
    update: function (userId, doc) {
        return doc.creatorId == userId
    },
    download: function (userId, doc) {
        return doc.creatorId == userId
    }
});

Merci à Raz pour cet excellent exemple. Vous voudrez consulter la documentation complète de CollectionFS pour plus de détails sur ce que peut faire CollectionFS.

Téléchargement de serveur

Les scripts suivants permettent de télécharger un fichier du système de fichiers du serveur sur le serveur. Principalement pour les fichiers de configuration et les gestionnaires de fichiers.

//https://forums.meteor.com/t/read-file-from-the-public-folder/4910/5

// Asynchronous Method.
Meteor.startup(function () {
    console.log('starting up');

    var fs = Npm.require('fs');
    // file originally saved as public/data/taxa.csv
    fs.readFile(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8', function (err, data) {
        if (err) {
            console.log('Error: ' + err);
            return;
        }

        data = JSON.parse(data);
        console.log(data);
    });
});


// Synchronous Method.
Meteor.startup(function () {
    var fs = Npm.require('fs');
    // file originally saved as public/data/taxa.csv
    var data = fs.readFileSync(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8');

    if (Icd10.find().count() === 0) {
        Icd10.insert({
            date:  new Date(),
            data:  JSON.parse(data)
        });
    }
});


Meteor.methods({
  parseCsvFile:function (){
    console.log('parseCsvFile');

    var fs = Npm.require('fs');
    // file originally saved as public/data/taxa.csv
    var data = fs.readFileSync(process.cwd() + '/../web.browser/app/data/taxa.csv', 'utf8');
    console.log('data', data);
  }
});


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow