Хранилище nodejs multer для удаления файла после сохранения на диск

Я использую хранилище дисков Multer для сохранения файла на диск. Сначала я сохраняю его на диск и выполняю некоторые операции с файлом, а затем загружаю его в удаленное ведро, используя другую функцию и lib. Как только загрузка будет завершена, я хотел бы удалить ее с диска.

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

5 ответов

Вам не нужно использовать 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!")
})

Мултер не нужен. Просто используйте этот код.

const fs = require('fs')

const path = './file.txt'

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

  //file removed
})

Я удалил каталог после загрузки файла с помощью fs-extra

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

// after you uploaded to bucket

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

Чтобы сделать это действительно автоматически на всех маршрутах, я использовал эту стратегию:

когда запрос заканчивается, мы удаляем все загруженные файлы (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);
        }
    });

Вы также можете рассмотреть возможность использования MemoryStorage для этой цели, с этим хранилищем файл никогда не сохраняется на диске, а в памяти и автоматически удаляется из памяти после того, как выполнение выходит из блока контроллера, то есть после того, как вы обслужите ответ в большей части случаи.

Когда вы будете использовать этот вариант хранения, вы не получите поля file.destination, file.path и file.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 документация:

ПРЕДУПРЕЖДЕНИЕ. Очень быстрая загрузка очень больших файлов или относительно небольших файлов в большом количестве может привести к тому, что вашему приложению будет не хватать памяти при использовании хранилища памяти.

Другие вопросы по тегам