如何使用Multer存储具有文件扩展名的文件?

86

我已经成功将文件存储到文件夹中,但它们没有文件扩展名。

有谁知道如何存储带有文件扩展名的文件吗?

18个回答

208

我有一个解决文件添加正确扩展名的方法。如果你使用path节点模块

var multer = require('multer');
var path = require('path')

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, Date.now() + path.extname(file.originalname)) //Appending extension
  }
})

var upload = multer({ storage: storage });

12
这是最佳解决方案。 - aidonsnous
3
这是一个非常棒的解决方案,感谢您分享。 - Cacoon
2
这个解决方案存在问题,它没有考虑到没有文件扩展名的文件。在这种情况下,您需要使用文件的 MIME 类型。 - m.e.conroy
1
我同意,这是最好的解决方案。为了找到正确的扩展名,您可以利用mime-types。https://www.npmjs.com/package/mime-types - Rafael Mejía
这应该是被接受的答案,谢谢! - jvbs
这对我也有效。使用 _path.extname(file.originalname)_,您无需提供点(.)来构建文件名。 - yaach

58

文档中提到:“Multer 不会为您附加任何文件扩展名,你的函数应该返回一个包含文件扩展名的完整文件名。”

以下是如何添加扩展名的方法:

var multer = require('multer');

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

var upload = multer({ storage: storage });

我建议使用mimetype属性来确定扩展名。例如:

filename: function (req, file, cb) {
  console.log(file.mimetype); //Will return something like: image/jpeg

更多信息:https://github.com/expressjs/multer


1
我按照这个方法操作,但我的文件被上传到了电脑的C盘uploads文件夹中。如何将它们保存到我的项目目录中? - kisor
1
@kisor 你想要的是 _dirname - Scott
2
这个答案只是指出Multer不会附加文件扩展名,但OP要求一种附加扩展名的方法。建议是有效的,但并没有回答主要问题。 - Jean Paul Rumeau

22

我从file.mimetype中获取了文件扩展名。我将mimetype拆分并从中得到了文件扩展名,请尝试下面的函数。

let storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './uploads')
  },
  filename: function (req, file, cb) {
    let extArray = file.mimetype.split("/");
    let extension = extArray[extArray.length - 1];
    cb(null, file.fieldname + '-' + Date.now()+ '.' +extension)
  }
})
const upload = multer({ storage: storage })

2
如果您尝试上传.docx文件,则此解决方案存在问题,该方法将失败。 - pratham kesarkar

13

可以这样做:

var storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, config.DIR)
    },
    filename: function (req, file, cb) {
        let ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length);
        cb(null, Date.now() + ext)
    }
});
const upload = multer({
    storage: storage
}).any();

为什么你提到了2018,它只是一个子字符串,对吧。 - Saahithyan Vigneswaran
我不记得为什么提到2018年,因为现在已经是2019年了。 - Zohaib Aslam
这个问题是因为文件名中没有包含文件的扩展名而导致的。你应该在某种程度上使用文件的MIME类型。 - m.e.conroy

9
import multer from 'multer';
import * as shortid from 'shortid';
import * as mime from 'mime-types';

const storage = multer.diskStorage({
  destination: function (req,file,cb) {
    cb(null, '/path/to/uploads/');
  },
  filename: function (req,file,cb) {
    /* generates a "unique" name - not collision proof but unique enough for small sized applications */
    let id = shortid.generate();
    /* need to use the file's mimetype because the file name may not have an extension at all */
    let ext = mime.extension(file.mimetype);
    cb(null, `${id}.${ext}`);
  }
});

编辑

shortid已被弃用,您应该使用nanoid。

import multer from 'multer';
import * as nanoid from 'nanoid';
import * as mime from 'mime-types';

const storage = multer.diskStorage({
  destination: function (req,file,cb) {
    cb(null, '/path/to/uploads/');
  },
  filename: function (req,file,cb) {
    /* generates a "unique" name - not collision proof but unique enough for small sized applications */
    let id = nanoid();
    /* need to use the file's mimetype because the file name may not have an extension at all */
    let ext = mime.extension(file.mimetype);
    cb(null, `${id}.${ext}`);
  }
});

你可以使用DateTime来生成唯一的名称,可选择与这个nanoid合并。 - undefined

5
我使用了这个小技巧来获取文件扩展名,并作为一个解决方法,来避免在有人上传两个相似文件名或存在于服务器中的文件时可能出现的问题。
const path = require('path');
const crypto = require('crypto');

let upload = multer({
storage: multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, path.join(__dirname, '../uploads'))
    },
    filename: (req, file, cb) => {
        // randomBytes function will generate a random name
        let customFileName = crypto.randomBytes(18).toString('hex')
        // get file extension from original file name
        let fileExtension = path.extname(file.originalname).split('.')[1];
        cb(null, customFileName + '.' + fileExtension)
    }
  })
})

文件名中如果有多个点会怎样呢? - jdrake
@JDrake,请检查更新后的答案,我已经为此提供了修复。 - Danny Sofftie

4

已经回答的代码可能存在一些问题。

  • 可能会出现没有扩展名的文件的情况。
  • 不应该使用upload.any(),它容易受到攻击者的攻击
  • 上传功能应该不是全局的

我编写了以下代码以提高安全性。

var storage = multer.diskStorage({
    destination: function (req, file, cb) {

        cb(null, 'temp/')
    },
    filename: function (req, file, cb) {
        let ext = ''; // set default extension (if any)
        if (file.originalname.split(".").length>1) // checking if there is an extension or not.
            ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length);
        cb(null, Date.now() + ext)
    }
})
var upload = multer({ storage: storage });

使用它进行上传

// using only single file object name (HTML name attribute)
// May use upload.array(["file1","file2"]) for more than one
app.post('/file_upload', upload.single("file"), function (req,res) {
    //console.log(req.body, 'Body');
    console.log(req.file, 'file');
    res.send("cool");
})

1
感谢您在这里的回答,但这并没有解答问题。如果您想在 StackOverflow 上存储这个知识,请考虑发布一个新问题并自我回答它。在此之前,请阅读帮助部分。 - Graham

2

const multer = require('multer'); const uuid = require('uuid/v1');

常量multer = require('multer'); 常量uuid = require('uuid / v1');

const MIME_TYPE_MAP = {
  'image/png': 'png',
  'image/jpeg': 'jpeg',
  'image/jpg': 'jpg'
};

const fileUpload = multer({
  limits: 500000,
  storage: multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, 'uploads/images');
    },
    filename: (req, file, cb) => {
      const ext = MIME_TYPE_MAP[file.mimetype];
      cb(null, uuid() + '.' + ext);
    }
  }),
  fileFilter: (req, file, cb) => {
    const isValid = !!MIME_TYPE_MAP[file.mimetype];
    let error = isValid ? null : new Error('Invalid mime type!');
    cb(error, isValid);
  }
});

module.exports = fileUpload;

2
文件扩展名可以是动态的。 这里是解决方案。
const path = require('path'); // path for cut the file extension
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, 'uploads')
    },
    filename: function (req, file, cb) {
      cb(null, 'upload_at_' + Date.now() + path.extname(file.originalname))
    }
  })

1
我使用这种方法,它很有效。
我将文件以以下格式存储: FieldName+Date+Extension => Profile1621416613594.jpg
var multer = require('multer');
    
var storage = multer.diskStorage({
    destination: function (req,file,cb){
        cb(null, './uploads')
    },
    filename: function (req,file,cb){
        cb(null,file.fieldname+'-'+Date.now()+'.'+file.mimetype.split('/').reverse()[0]);
    },
});

var upload = multer({storage: storage}); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接