Node.js Multer磁盘存储:保存到磁盘后删除文件

17

我正在使用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的remove函数来删除临时文件夹中的文件? 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 };
5个回答

49

您不需要使用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!")
})

谢谢你提供这个好的解决方案。但我已经决定将其拆分成模块化的形式。请查看更新内容。我如何在这里仍然应用你的解决方案?感谢建议。 - jacky
3
这是一个很棒的解决方案。+1 使用 prettify,+1 指出我们只需要取消链接 req.file.path。我学到了两个新东西(在看到这个之前,我昨天还在手动封装 fs 方法以便与 async-await 一起使用)。 - user3773048
1
Node 10.23.1 版本开始,你可以直接使用 const fs = require('fs').promises - kokoko
删除文件后使用res.end("UPLOAD COMPLETED!")是否安全?因为这样可以提高响应时间。 - Rajan
你也可以使用fs.unlinkSync(path)方法,它会同步执行相同的操作(无需使用Promise)。 - Tarik Merabet
unlinkAsync 不再使用,但是有 fs.unlink 是默认异步的,还有 fs.unlinkSync 是同步的。 - Syed M. Sannan

15

不需要使用Multer。只需使用这段代码。

const fs = require('fs')

const path = './file.txt'

fs.unlink(path, (err) => {
  if (err) {
    console.error(err)
    return
  }

  //file removed
})

1
对于那些不是 Promise 和 promisify 大师的人来说非常有用 - 你需要为 promisify 和 promises 添加一些自定义内容,如果不需要可能会很困惑。 - J.E.C.

1

我使用fs-extra上传文件后删除了目录

const fs = require('fs-extra');

// after you uploaded to bucket

await fs.remove('uploads/abc.png'); // remove upload dir when uploaded bucket

0

要真正地在所有路由上自动执行,我使用了这种策略:

当请求结束时,我们会删除所有已上传的文件(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);
        }
    });

0

您也可以考虑使用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 文档中所提到的那样,它也有一个缺点:

警告:上传非常大的文件,或者相对较小的文件以非常快的速度大量上传,当使用内存存储时,可能会导致应用程序耗尽内存。


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