【问题标题】:Nodejs save uploaded fileNodejs保存上传的文件
【发布时间】:2019-08-02 21:27:28
【问题描述】:

我有一个应用程序,在该应用程序中,我想使用一些文件上传机制。

我的要求是:

文件上传后,其名称将更改为唯一名称,例如 uuid4()。稍后我会将这个名称存储在数据库中。

我已经写了类似的东西,但是我有几个问题:

const multer = require('multer');
const upload = multer();
router.post('/', middleware.checkToken, upload.single('file'), (req,res,next)=>{

    // key:
    // file : "Insert File Here"

    console.log("req:");
    console.log(req.file);
    const str = req.file.originalname
    var filename = str.substring(0,str.lastIndexOf('.'));
    // I will use filename and uuid for storing it in the database
    // I will generate unique uuid for the document and store the document
    // with that name
    var extension = str.substring(str.lastIndexOf('.') + 1, str.length);

    // HERE!

    res.status(200).json();

})

我见过将它存储在 diskStorage 中的示例:

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, '/tmp/my-uploads')
    },
    filename: function (req, file, cb) {
        cb(null, file.fieldname + '-' + Date.now())
  }
})

var upload = multer({ storage: storage })

但是,据我了解,这是 API 调用之外的配置。这意味着我每次调用此 API 时都无法修改它。我想为文件分配不同的名称,我需要该名称(uuid)将该名称保存在数据库中。

我怎样才能保留这样的功能?

【问题讨论】:

  • 每次上传文件时都会调用 filename,因此您会得到不同的标识符。然后,新名称应该可以在req.file
  • @Rashomon,所以,如果我将名称表示为 uuid,我可以通过 API 调用 req.file.fieldname? 获得此名称
  • 我面前有一个工作示例,它存储在一个名为 filename yes 的属性中。它不完全一样,因为我使用多上传

标签: node.js mongoose multer


【解决方案1】:
  1. 不需要。因为您使用的是时间戳。

  2. 如果保存到数据库时出错,您可以使用此代码删除上传的文件以避免将来发生冲突。试试这个:

    const multer = require('multer');
    const fs = require('fs'); // add this line
    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
            // the file is saved to here
            cb(null, '/PATH/TO/FILE')
        },
        filename: function (req, file, cb) {
            // the filename field is added or altered here once the file is uploaded
            cb(null, uuidv4() + '.xlsx')
        }
    })
    var upload = multer({ storage: storage })
    
    
    router.post('/', middleware.checkToken, upload.single('file'), (req,res,next)=>{
        // the file is taken from multi-form and the key of the form must be "file"
    
        // visible name of the file, which is the original, uploaded name of the file
        const name = req.file.originalname;
    
        // name of the file to be stored, which contains unique uuidv4
        const fileName = req.file.filename;
        // get rid of the extension of the file ".xlsx"
        const file_id = fileName.substring(0, fileName.lastIndexOf('.'));
    
        // TODO
        // Right now, only xlsx is supported
        const type = "xlsx";
    
        const myObject = new DatabaseObject({
            _id : new mongoose.Types.ObjectId(),
            file_id: file_id,
            name : name,
            type: "xlsx"
        })
    
        myObject .save()
        .then(savedObject=>{
            // return some meaningful response
        }).catch(err=>{
            // add this
            // Assuming that 'path/file.txt' is a regular file.
            fs.unlink('path/file.txt', (err) => {
               if (err) throw err;
               console.log('path/file.txt was deleted');
            });
        })
    })
    

另见NodeJS File System Doc

【讨论】:

    【解决方案2】:

    感谢@Rashomon 和@Eimran Hossain Eimon,我已经解决了这个问题。如果有人想知道解决方案,这里是:

    const multer = require('multer');
    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
            // the file is saved to here
            cb(null, '/PATH/TO/FILE')
        },
        filename: function (req, file, cb) {
            // the filename field is added or altered here once the file is uploaded
            cb(null, uuidv4() + '.xlsx')
        }
    })
    var upload = multer({ storage: storage })
    
    
    router.post('/', middleware.checkToken, upload.single('file'), (req,res,next)=>{
        // the file is taken from multi-form and the key of the form must be "file"
    
        // visible name of the file, which is the original, uploaded name of the file
        const name = req.file.originalname;
    
        // name of the file to be stored, which contains unique uuidv4
        const fileName = req.file.filename;
        // get rid of the extension of the file ".xlsx"
        const file_id = fileName.substring(0, fileName.lastIndexOf('.'));
    
        // TODO
        // Right now, only xlsx is supported
        const type = "xlsx";
    
        const myObject = new DatabaseObject({
            _id : new mongoose.Types.ObjectId(),
            file_id: file_id,
            name : name,
            type: "xlsx"
        })
    
        myObject .save()
        .then(savedObject=>{
            // return some meaningful response
        }).catch(err=>{
            // return error response
        })
    })
    

    这解决了我当前的问题。感谢您的帮助。为了将来的改进,我将添加错误案例:

    • 如果 uuidv4 返回一个已经存在的 id(我认为这是极不可能的,因为该对象包含一些时间戳数据),请重新运行重命名函数。

    • 如果保存到数据库时出错,我应该删除上传的文件以避免将来发生冲突。

    如果您也有这些问题的解决方案,我将不胜感激。

    【讨论】:

    • 1:如果您已经使用了长时间戳就足够了。 2:如果保存到数据库时出错,请在save()函数上捕获错误并删除带有filename名称的文件
    【解决方案3】:

    我认为你错了......你说的是

    我不能每次调用这个 API 时都修改它。

    但实际上,每个文件每次都会调用filename。让我解释一下这部分代码...

    filename: function (req, file, cb) {
            cb(null, file.fieldname + '-' + Date.now())
      }
    

    这里看callback函数(用cb表示):

    • 回调函数中的第一个参数null 类似于约定。您总是将null 作为回调函数中的第一个参数传递。 See this Reference
    • 第二个参数决定了destination 文件夹中文件的名称。 因此,您可以在此处指定任何函数,该函数每次都可以为您返回一个唯一文件名。

    由于您使用的是猫鼬... 我认为如果您在架构中使用mongoose method 实现function uniqueFileName() 并在路由处理程序中调用它会更好。 Learn More

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 2019-09-15
      • 2011-07-07
      • 2013-08-23
      • 2012-03-09
      • 2021-11-01
      • 1970-01-01
      相关资源
      最近更新 更多