【问题标题】:Uploading files using Skipper with Sails.js v0.10 - how to retrieve new file name使用带有 Sails.js v0.10 的 Skipper 上传文件 - 如何检索新文件名
【发布时间】:2014-06-01 05:23:52
【问题描述】:

我正在升级到Sails.js 0.10 版,现在需要使用Skipper 来管理我的文件上传。

当我上传一个文件时,我使用 UUID 为其生成一个新名称,并将其保存在 public/files/ 文件夹中(当我完成所有工作时,这将改变,但它现在有利于测试)

我把原来的名字和上传的名字+路径保存到一个Mongo数据库中。

Sails v0.9.x 下这一切都非常简单,但使用Skipper 我不知道如何读取新文件名和路径。 (显然,如果我能读懂名字,我就可以构建路径,所以它实际上只是我需要的名字)

我的控制器看起来像这样

var uuid = require('node-uuid'),
    path = require('path'),
    blobAdapter = require('skipper-disk');

module.exports = {

  upload: function(req, res) {

    var receiver = blobAdapter().receive({
          dirname: sails.config.appPath + "/public/files/",
          saveAs: function(file) {
            var filename = file.filename,
                newName = uuid.v4() + path.extname(filename);
            return newName;
          }
        }),
        results = [];

    req.file('docs').upload(receiver, function (err, files) {
      if (err) return res.serverError(err);
      async.forEach(files, function(file, next) {
        Document.create({
          name: file.filename,
          size: file.size,
          localName: // ***** how do I get the `saveAs()` value from the uploaded file *****,
          path: // *** and likewise how do i get the path ******
        }).exec(function(err, savedFile){
          if (err) {
            next(err);
          } else {
            results.push({
              id: savedFile.id,
              url: '/files/' + savedFile.localName
            });
            next();
          }
        });
      }, function(err){
        if (err) {
          sails.log.error('caught error', err);
          return res.serverError({error: err});
        } else {
          return res.json({ files: results });
        }
      });
    });
  },

  _config: {}

};

我该怎么做?

【问题讨论】:

    标签: javascript file-upload sails.js multifile-uploader skipper


    【解决方案1】:

    我现在已经解决了这个问题,并认为我会分享我的解决方案,以帮助其他遇到类似问题的人。

    解决方案是根本不使用skipper-disk,而是编写我自己的自定义receiver。我已将其创建为 Sails Service 对象。

    所以在文件api/services/Uploader.js

    // Uploader utilities and helper methods
    // designed to be relatively generic.
    
    var fs = require('fs'),
        Writable = require('stream').Writable;
    
    exports.documentReceiverStream = function(options) {
      var defaults = {
        dirname: '/dev/null',
        saveAs: function(file){
          return file.filename;
        },
        completed: function(file, done){
          done();
        }
      };
    
      // I don't have access to jQuery here so this is the simplest way I
      // could think of to merge the options.
      opts = defaults;
      if (options.dirname) opts.dirname = options.dirname;
      if (options.saveAs) opts.saveAs = options.saveAs;
      if (options.completed) opts.completed = options.completed;
    
      var documentReceiver = Writable({objectMode: true});
    
      // This `_write` method is invoked each time a new file is received
      // from the Readable stream (Upstream) which is pumping filestreams
      // into this receiver.  (filename === `file.filename`).
      documentReceiver._write = function onFile(file, encoding, done) {
        var newFilename = opts.saveAs(file),
            fileSavePath = opts.dirname + newFilename,
            outputs = fs.createWriteStream(fileSavePath, encoding);
        file.pipe(outputs);
    
        // Garbage-collect the bytes that were already written for this file.
        // (called when a read or write error occurs)
        function gc(err) {
          sails.log.debug("Garbage collecting file '" + file.filename + "' located at '" + fileSavePath + "'");
    
          fs.unlink(fileSavePath, function (gcErr) {
            if (gcErr) {
              return done([err].concat([gcErr]));
            } else {
              return done(err);
            }
          });
        };
    
        file.on('error', function (err) {
          sails.log.error('READ error on file ' + file.filename, '::', err);
        });
    
        outputs.on('error', function failedToWriteFile (err) {
          sails.log.error('failed to write file', file.filename, 'with encoding', encoding, ': done =', done);
          gc(err);
        });
    
        outputs.on('finish', function successfullyWroteFile () {
          sails.log.debug("file uploaded")
          opts.completed({
            name: file.filename,
            size: file.size,
            localName: newFilename,
            path: fileSavePath
          }, done);
        });
      };
    
      return documentReceiver;
    }
    

    然后我的controller 就变成了(api/controllers/DocumentController.js

    var uuid = require('node-uuid'),
        path = require('path');
    
    module.exports = {
    
      upload: function(req, res) {
    
        var results = [],
            streamOptions = {
              dirname: sails.config.appPath + "/public/files/",
              saveAs: function(file) {
                var filename = file.filename,
                    newName = uuid.v4() + path.extname(filename);
                return newName;
              },
              completed: function(fileData, next) {
                Document.create(fileData).exec(function(err, savedFile){
                  if (err) {
                    next(err);
                  } else {
                    results.push({
                      id: savedFile.id,
                      url: '/files/' + savedFile.localName
                    });
                    next();
                  }
                });
              }
            };
    
        req.file('docs').upload(Uploader.documentReceiverStream(streamOptions),
          function (err, files) {
            if (err) return res.serverError(err);
    
            res.json({
              message: files.length + ' file(s) uploaded successfully!',
              files: results
            });
          }
        );
      },
    
      _config: {}
    };
    

    我确信它可以进一步改进,但这对我来说非常有效。

    【讨论】:

      【解决方案2】:

      上传的文件对象包含你需要的所有数据:

      req.file('fileTest').upload({
        // You can apply a file upload limit (in bytes)
        maxBytes: maxUpload,
        adapter: require('skipper-disk')
      }, function whenDone(err, uploadedFiles) {
        if (err) {
          var error = {  "status": 500, "error" : err };
          res.status(500);
          return res.json(error);
        } else {
          for (var u in uploadedFiles) {
            //"fd" contains the actual file path (and name) of your file on disk
            fileOnDisk = uploadedFiles[u].fd;
            // I suggest you stringify the object to see what it contains and might be useful to you
            console.log(JSON.stringify(uploadedFiles[u]));
          }
        }
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-20
        • 1970-01-01
        • 2011-11-07
        • 2019-09-08
        • 2011-04-08
        • 2014-11-08
        相关资源
        最近更新 更多