【问题标题】:How to store a file with file extension with multer?如何使用 multer 存储具有文件扩展名的文件?
【发布时间】:2015-10-14 01:48:30
【问题描述】:

设法将我的文件存储在一个文件夹中,但它们存储时没有文件扩展名。

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

【问题讨论】:

    标签: node.js express npm multer


    【解决方案1】:

    简单的辅助函数,维护 multer 生成的唯一文件名并添加从 mimetype 解析的扩展名:

    只需传递multer返回的对象


    const fs = require('fs');
    
    function renameWithExt(file) {
      const ext = file.mimetype.split('/')[1]; // parse the extension type
    
      fs.rename(`${file.path}`, `${file.path}.${ext}`, () => {
        console.log(`File: ${file.filename} renamed with extension '.${ext}'`);
      });
    }
    
    renameWithExt(req.file);
    
    

    【讨论】:

      【解决方案2】:

      const multer = require('multer');
      const 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;

      【讨论】:

        【解决方案3】:

        const multer = require('multer'); const 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;
        

        【讨论】:

          【解决方案4】:

          可以这样操作...简单易懂

          // validate uploaded files
          const FILE_TYPE_MAP = {
            // mime type
            "image/png": "png",
            "image/jpeg": "jpeg",
            "image/jpg": "jpg",
          };
          const storage = multer.diskStorage({
            destination: function (req, file, cb) {
              cb(null, "public/uploads");
            },
            filename: function (req, file, cb) {
              const filename = file.originalname.replace(" ", "-");
              const extension = FILE_TYPE_MAP[file.mimetype]
              cb(null, `${filename}-${Date.now()}.${extension}`);
            },
          });
          

          【讨论】:

          • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
          • 这行得通。但是,我上传 .jpeg 还是 .jpg 并不重要。我总是以扩展名 .jpeg 结尾。
          【解决方案5】:

          我用这个方法,效果很好。

          我以这种格式存储文件: 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}); 
          

          【讨论】:

            【解决方案6】:

            可以这样做:

            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,它只是一个子字符串吧
            • 我不记得为什么提到 2018 年了,因为现在是 2019 年。
            • 这会受到文件名中没有扩展名的文件名的影响。您应该以某种方式使用 mimetype。
            【解决方案7】:
            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}`);
              }
            });
            

            【讨论】:

              【解决方案8】:

              我喜欢将原始文件名用于 SEO。这需要更多检查是否已存在同名文件。 此外,扩展解析只需几个步骤即可提供最大的灵活性。

              var storage = multer.diskStorage({
                destination: function (req, file, cb) {
                  cb(null, 'uploads/')
                },
                filename: function (req, file, cb) {
                  // try to get extension from original file name
                  var lioDot = file.originalname.lastIndexOf('.');
                  if (lioDot !== -1) {
                    // I like to use original upload filename for SEO but first lets clean it 
                    var newName = file.originalname.substring(0, lioDot).replace(/([^a-z0-9]+)/gi, '-');
                    var ext = file.originalname.substring(lioDot, file.originalname.length);
                  } else {
                    var newName = file.originalname.replace(/([^a-z0-9]+)/gi, '-');
                    // try to get extension from mime type string
                    var extArray = file.mimetype.split("/");
                    var ext = extArray[extArray.length - 1];
                    // mime type extension resolving by pure string extraction is not accurate for a lot of types
                    // https://www.freeformatter.com/mime-types-list.html
                    // it's usually fine for ext strings up to 4 characters, png, jpeg, gif, bmp, tiff ..
                    if (ext > 4) {
                      // other mime types you would like to support
                      var mimetypes = { 'vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx' };
                      if (mimetypes.hasOwnProperty(ext)) ext = mimetypes[ext];
                    }
                  }
              
                  var newFullName = newName + ext;
                  var i = 0;
                  // we need to check if the file with the same name already exists
                  // if it exists then we're adding something to make it unique 
                  while (fs.existsSync(process.env.PWD + '/uploads/' + newFullName)) {
                    newFullName = newName + '-' + ++i + ext;
                  }
                  cb(null, newFullName);
                }
              })
              
              const upload = multer({ storage: storage });
              

              【讨论】:

                【解决方案9】:

                文件扩展名可以是动态的。 这是解决方案

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

                【讨论】:

                  【解决方案10】:

                  我使用这个小技巧来获取文件扩展名,并作为一种解决方法来规避当有人上传具有相似文件名的文件两次或服务器中存在的文件时可能出现的问题。

                  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 检查更新的答案,我更新了解决方案
                  【解决方案11】:

                  我有一个解决方法来添加正确的文件扩展名。如果你使用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 });
                  

                  【讨论】:

                  • 这是最好的解决方案
                  • 这是一个绝妙的解决方案,感谢您分享它
                  • 这个解决方案有问题,它不考虑没有文件扩展名的文件。在这种情况下,您需要使用文件的 mime 类型。
                  • 我同意,这是最好的解决方案。为了找出正确的扩展名,您可以使用 mime-types。 npmjs.com/package/mime-types
                  • 这应该是公认的答案,谢谢!!
                  【解决方案12】:

                  一种面向对象的方式来存储具有唯一名称的图像

                  // image.service.ts
                  import { diskStorage, StorageEngine } from "multer";
                  
                  class ImageStorageService {
                  
                      storage: StorageEngine
                      constructor() {
                          const MIME_TYPE_MAP = {
                              'image/png': 'png',
                              'image/jpeg': 'jpg',
                              'image/jpg': 'jpg'
                          }
                  
                          this.storage = diskStorage({
                              destination: (req, file, callback) => {
                                  const isValid = MIME_TYPE_MAP[file.mimetype]
                                  let error = new Error(`Invalid mime type`)
                                  if (isValid)
                                      error = null
                  
                                  //app.use(express.static(path.join(`${__dirname}/assets`)))
                                  callback(error, 'assets/images')
                              },
                              filename: (req, file, callback) => {
                                  let currentFileName: string = file.originalname.substr(0, file.originalname.lastIndexOf('.'))
                                  const name = currentFileName.toLowerCase().split(' ').join('-')
                                  const ext = MIME_TYPE_MAP[file.mimetype]
                                  callback(null, `${name}-${Date.now()}.${ext}`)
                              }
                          })
                      }
                  }
                  
                  export const ImageStorage = new ImageStorageService().storage
                  

                  然后在你的一条路线中

                  import { ImageStorage } from "./services/image-storage.service";
                  
                  this.router.post('/signup', multer({ storage: ImageStorage }).single('image'), async (req, res, next) => {
                      let img_url: string
                      if (req.file) {
                          const url: string = `${req.protocol}:\/\/${req.get('host')}`
                          img_url = url + '/images/' + req.file.filename
                          //http://localhost:3000/images/penguins-1548339248380.jpg
                      }
                  })
                  

                  【讨论】:

                    【解决方案13】:

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

                    • 可能存在文件没有扩展名的某些情况。
                    • 不应有 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");
                    })
                    

                    【讨论】:

                    • 感谢您在这里输入,但这并不能回答问题。如果您想将这些知识存储在 StackOverflow 上,请考虑发布一个新问题并自行回答。在做之前还要阅读帮助部分。
                    【解决方案14】:

                    我就是这样的

                    var multer  = require('multer');
                    
                    var storage = multer.diskStorage({
                      destination: function (req, file, cb) {
                        cb(null, './public/uploads/img/')
                      },
                      filename: function (req, file, cb) {
                        let ext = file.originalname.substring(file.originalname.lastIndexOf('.'), file.originalname.length);
                        cb(null, Date.now() + ext);
                      }
                    })
                    
                    var upload = multer({ storage: storage }).single('eventimage');
                    

                    【讨论】:

                    • 如果文件名中有多个点怎么办?
                    • 文件名没有扩展名怎么办?
                    【解决方案15】:

                    我从 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 })
                    

                    【讨论】:

                    • 如果您尝试上传 .docx 文件而不是此方法失败,则此解决方案存在问题
                    【解决方案16】:

                    来自文档:“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

                    【讨论】:

                    • 我遵循这个,但我的文件上传到我电脑的 C: 驱动器的上传文件夹下。如何将它们保存在我的项目目录中。
                    • @kisor 你关注_dirname
                    • 这个答案只是指出 Multer 没有附加文件扩展名,但 OP 要求一种附加扩展名的方法。建议有效,但没有回答主要问题。
                    猜你喜欢
                    • 2017-06-27
                    • 2020-06-10
                    • 1970-01-01
                    • 2020-02-24
                    • 1970-01-01
                    • 2021-12-13
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-10-25
                    相关资源
                    最近更新 更多