【问题标题】:nodejs multer diskstorage to delete file after saving to disknodejs multer diskstorage在保存到磁盘后删除文件
【发布时间】:2018-08-12 11:25:02
【问题描述】:

我正在使用 multer 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 }).single('file')

这是我的使用方法:

app.post('/api/photo', function (req, res) {
    upload(req, res, function (err) {
        uploadToRemoteBucket(req.file.path)
        .then(data => {
            // delete from disk first

            res.end("UPLOAD COMPLETED!");
        })
    })
});

如何使用 diskStorage 删除功能删除临时文件夹中的文件? https://github.com/expressjs/multer/blob/master/storage/disk.js#L54

更新:

我决定将其模块化并放在另一个文件中:

const fileUpload = function(req, res, cb) {
    upload(req, res, function (err) {
        uploadToRemoteBucket(req.file.path)
        .then(data => {
            // delete from disk first

            res.end("UPLOAD COMPLETED!");
        })
    })
}

module.exports = { fileUpload };

【问题讨论】:

    标签: javascript node.js express multer


    【解决方案1】:

    为了在所有路线上真正自动完成,我使用了这个策略:

    当请求结束时,我们删除所有上传的文件(req.files)。在此之前,如果要将文件保留在服务器上,则需要将它们保存在另一个路径中。

    var express = require('express');
    var app = express();
    var http = require('http');
    var server = http.Server(app);
    
    // classic multer instantiation
    var multer = require('multer');
    var upload = multer({
        storage: multer.diskStorage({
            destination: function (req, file, cb) {
                cb(null, `${__dirname}/web/uploads/tmp/`);
            },
            filename: function (req, file, cb) {
                cb(null, uniqid() + path.extname(file.originalname));
            },
        }),
    });
    app.use(upload.any());
    
    // automatically deletes uploaded files when express finishes the request
    app.use(function(req, res, next) {
        var writeHead = res.writeHead;
        var writeHeadbound = writeHead.bind(res);
        res.writeHead = function (statusCode, statusMessage, headers) {
            if (req.files) {
                for (var file of req.files) {
                    fs.unlink(file.path, function (err) {
                        if (err) console.error(err);
                    });
                }
            }
    
            writeHeadbound(statusCode, statusMessage, headers);
        };
    
        next();
    });
    
    // route to upload a file
        router.post('/profile/edit', access.isLogged(), async function (req, res, next) {
            try {
    
    // we copy uploaded files to a custom folder or the middleware will delete them
                for (let file of req.files)
                    if (file.fieldname == 'picture')
                        await fs.promises.copy(file.path, `${__dirname}/../uploads/user/photo.jpg`);
    
            } catch (err) {
                next(err);
            }
        });
    

    【讨论】:

      【解决方案2】:

      您也可以考虑为此目的使用MemoryStorage,使用此存储,文件永远不会存储在磁盘中,而是存储在内存中,并且在执行完控制器块后自动从内存中删除,即在您为在大多数情况下都有响应。

      当您使用此存储选项时,您不会得到字段file.destinationfile.pathfile.filename,而是会得到字段file.buffer,顾名思义是一个缓冲区,您可以转换将此缓冲区转换为所需的格式以进行操作,然后使用流对象上传。

      大多数流行的库都支持流,因此您应该能够使用流直接上传文件,将缓冲区转换为流的代码:

      const Readable = require('stream').Readable;
      
      var stream = new Readable();
      stream._read = () => { }
      stream.push(file.buffer);
      stream.push(null);
      
      // now you can pass this stream object to your upload function
      

      这种方法会更有效,因为文件将存储在内存中,这将导致更快的访问,但它确实有multer文档中提到的缺点:

      警告:上传非常大的文件,或相对较小的文件 非常快的大量数字,可能会导致您的应用程序用完 使用内存存储时的内存。

      【讨论】:

        【解决方案3】:

        不需要穆特。只需使用此代码。

        const fs = require('fs')
        
        const path = './file.txt'
        
        fs.unlink(path, (err) => {
          if (err) {
            console.error(err)
            return
          }
        
          //file removed
        })
        

        【讨论】:

        • 对那些不精通 Promisify 和 Promisify 的人很有用 - 你需要为 Promisify 和 Promisify 添加一些自定义,如果不需要的话可能会造成混淆。
        【解决方案4】:

        您不需要使用multer 来删除文件,而且_removeFile 是一个您应该使用的私有函数。

        您可以像往常一样通过fs.unlink 删除文件。因此,无论您在哪里可以访问req.file,都可以执行以下操作:

        const fs = require('fs')
        const { promisify } = require('util')
        
        const unlinkAsync = promisify(fs.unlink)
        
        // ...
        
        const storage = multer.diskStorage({
            destination(req, file, cb) {
              cb(null, '/tmp/my-uploads')
            },
            filename(req, file, cb) {
              cb(null, `${file.fieldname}-${Date.now()}`)
            }
          })
        
        const upload = multer({ storage: storage }).single('file')
        
        app.post('/api/photo', upload, async (req, res) =>{
            // You aren't doing anything with data so no need for the return value
            await uploadToRemoteBucket(req.file.path)
        
            // Delete the file like normal
            await unlinkAsync(req.file.path)
        
            res.end("UPLOAD COMPLETED!")
        })
        

        【讨论】:

        • 感谢这个不错的解决方案。但我决定将其取出并使其模块化。请查看更新。我怎样才能在这里应用您的解决方案?感谢您的建议
        • 这是一个很棒的解决方案。 +1 使用 prettify,+1 指出我们只需要取消链接 req.file.path。我刚刚学到了两个新东西(在看到这个之前,从昨天开始手动将 fs 方法包装在与 async-await 一起使用的 Promise 中)。
        • 仅供参考,因为 Node 10.23.1 您可以直接使用 const fs = require('fs').promises
        • 在 res.end("UPLOAD COMPLETED!") 之后删除文件是否安全?因为这样响应时间会有所改善。
        • 你也可以使用 fs.unlinkSync(path),那个方法做同样的事情但是同步(不需要使用 promise)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-01-03
        • 2019-06-08
        • 2016-07-22
        • 2013-12-19
        • 2010-09-23
        • 2010-11-08
        • 1970-01-01
        相关资源
        最近更新 更多