Error: ENOENT: no such file or directory Nodejs - javascript

I'm trying to upload a file and store it in an uploads folder, but I get this error: no such file or directory
I get the message success in console but I get this error anyway.
POST /auth/register 500 21.023 ms - 260
Error: ENOENT: no such file or directory, open E:\IMPORTANT\INFO-DEV\DEV\ANGULAR NODEJS\API AUTH\uploads\1671534381494.jpeg
Here is my configuration code for upload.
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
const extension = path.extname(file.originalname);
cb(null, Date.now() + extension);
},
});
const upload = multer({
storage: storage,
fileFilter: function (req, file, callback) {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
callback(null, true);
console.log("Image téléchargé avec succès"); // success message
} else {
callback(null, false);
console.log("Seulement du fichier de type png, jpg ou jpeg"); // error message
}
},
limits: {
fileSize: 1024 * 1024 * 2,
},
});
module.exports = upload;

I got the same error, but I was able to solve it by getting my current path.
import multer from "multer";
// Set up multer storage options
const storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log("🚀 ~ file: upload.ts:11 ~ file", process.cwd());
cb(null, `${process.cwd()}/src/Images`);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
},
});
// Create a multer instance with the storage options
const upload = multer({ storage });
export default upload;

The issue is that your uploads folder doesn't exist or you set the path incorrectly.
I don't know where exactly you created uploads folder (and if you created it at all).
So in the destination param you should pass either:
path.join(__dirname, '/uploads') - in case that folder is in the same location where current js file is located.
Or path.join(process.cwd(), '/uploads') - in case if uploads folder is in the root of the project (where you run npm start etc.)
So, in short words you need to make sure folder exists and then make sure the path is correct.
P.S.
Using ../../ syntax should also work, you can try ../uploads or ../../uploads if, for example, that folder is on higher levels of your folders structure.

Change this line
cb(null, './uploads/');
this line
cb(null, "uploads/");
or try
cb(__dirname, "uploads/");

you can try your path name as like
img: {
data: fs.readFileSync(
path.join(__dirname + "../../uploads" + req.file.filename)
),
contentType: "image/png",
},

Related

In multer file extension which shouldnt be saved getting saved

TASK OF CODE : The code telling multer to save file with pdf extension
PROBLEM : I am getting back error in response but the file getting saved inside the folder
const express = require("express");
const app = new express();
const multer = require("multer");
const upload = multer({
dest: "images", // destination to save the image
limits: 100000, // limiting the size of file to 1mb and 1 mb = 100000bytes
fileFilter(req, file, cb) {
if (!file.originalname.endsWith("pdf")) {
cb(new Error("please upload PDF file extension")); // sending error
}
cb(undefined, true);
// 3 type of call backs
// cb(new Error('please upload PDF file extension'));// sending error
// cb(undefined,true)// undefined means no error and true means accepting file
// cb(undefined,false)// undefined means no error and true means rejecting file
},
});
app.post("/upload", upload.single("upload"), (req, res) => {
res.send();
});
app.listen(8000, () => {
console.log("server fired off");
});
The error message is correct as per what I want
enter image description here
But the file is getting saved in images folder which should not be saved because I am sending jpg extension
Looks like the problem is that the code execution continues after cb(new Error(..), thus cb(undefined,true) gets called as well, telling multer that everything is ok. Change it to:
if (!file.originalname.toLowerCase().endsWith("pdf")) {
return cb(new Error("please upload PDF file extension")); // sending error
}
cb(undefined, true);
Note that I also used .toLowerCase() just to be sure that files with a.PDF extension get uploaded.
I'm making this new function called checkFileType()
function checkFileType(file, cb){
const filetypes = /pdf/;
const extname = filetypes.test(file.originalname.split('.')[file.originalname.split('.').length-1]);
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
}else{
cb(error = 'message : please upload PDF file extension');
}
}
And I implemented it like this
const upload = multer({
dest: "images", // destination to save the image
limits: 100000, // limiting the size of file to 1mb and 1 mb = 100000bytes
fileFilter(req, file, cb) {
checkFileType(file, cb);
},
});

Custom file name from frontend in Multer

I'm uploading a file using FormData and receiving it server-side using Multer. Everything works as expected, except since I'm using FileSystem API on the front-end (https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem/webkitGetAsEntry), the files I'm uploading come from sub-directories. Multer seems to only see the filename, even if I explicitly set an alias for the file as I append it to form data (https://developer.mozilla.org/en-US/docs/Web/API/FormData/append). It also seems like Multer performs its logic prior to the rest of my request handler and does not see the parameters I set on the body. How do I get multer to see the full path?
Here is a simplified version of what I currently have setup:
Client (alias represents full name with path, file.name is the base name automatically set by FileSystem API):
function upload(file, alias) {
let url = window.location.origin + '/upload';
let xhr = new XMLHttpRequest();
let formData = new FormData();
xhr.open('POST', url, true);
return new Promise(function (resolve, reject) {
xhr.addEventListener('readystatechange', function(e) {
if (xhr.readyState == 4 && xhr.status == 200) {
resolve(file.name);
}
else if (xhr.readyState == 4 && xhr.status != 200) {
reject(file.name);
}
})
formData.append('file', file, alias || file.name); // this should in theory replace filename, but doesn't
formData.append('alias', alias || file.name); // an extra field that I can't see in multer function at all
xhr.send(formData);
});
}
Server:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
// neither req nor file seems to contain any hint of the alias here
cb(null, file.originalname);
}
});
const upload = multer({storage: storage});
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.post('/upload', upload.single('file'), function (req, res, next) {
// by this time the file seems to already be on disk with whatever name multer picked
if (req.file) {
res.status(200).end();
} else {
res.status(500).end();
}
});
In order to get this to work, use the preservePath option when configuring multer. The following will work:
const upload = multer({storage: storage, preservePath: true});
However, it's important to note, multer will not create the directories or subdirectories. Those have to be created beforehand. (I tested this too. If directories are created and empty, upload succeeds, however, if directories do not exist, uploads fail).
In their readme, they say:
"Note: You are responsible for creating the directory when providing destination as a function. When passing a string, multer will make sure that the directory is created for you."
A follow-up to that note would be: "you are responsible for creating any sub-directories too".
The relative paths of files uploaded will be accessible in originalname property. So, backend would look like this: (as you had it, but with updated comments)
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
// If you uploaded for example, the directory: myDir/myFile.txt,
// file.originalname *would* be set to that (myDir/myFile.txt)
// and myFile.txt would get saved to uploads/myDir
// *provided that* uploads/myDir already exists.
// (if it doesn't upload will fail)
// /* if( [ uploads/myDir doesn't exist ] ) { mkdir } */
cb(null, file.originalname);
}
});
Helpful tip:
On the front end, I found it easier to test directory / subdirectory upload with: (tested on Chrome latest ok)
<form action="/uploads/multipleFiles" method="post" enctype="multipart/form-data">
<input type="file" name="multiple" webkitdirectory accept="text/*" onchange="console.log(this.files)" />
<input type="text" name="tester" value="uploadTester" />
<input type="submit"/>
</form>
If you want to upload Passport image as a front and back side then pass parameter from frontend like this user:"username" and type:"front" OR type:"back"
then Use it in node side like this
const upload = multer({
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/passport/');
},
filename: function (req, file, cb) {
cb(null, req.body.user+"-"+req.body.type+".jpg");
}
})
});

set multer destination in api.js in nodejs and call another function?

i am using a api in server.js file.
app.post('/api/uploadalumniresume', api.UploadAlumniResume);
my api.js file code is:
exports.UploadAlumniResume = (req, res) => {
const storage = multer.diskStorage({
destination(req, file, cb) {
// cb(null, `${__dirname}public/images/uploads`);
cb(null, `${__dirname}/../public/imports`);
},
filename(req, file, cb) {
cb(null, `${Date.now()}-${file.originalname}`);
},
});
const importupload = multer({
storage,
});
const importmulter = importupload.single('file');
};
The server.js as call the api but the exports api not saving the uploading file to the destination folder
And i need to store the upload file on destination follder.
And if the file as uploaded then function need to work on create fuction in the same api.
please give a any solution to me!

Type of object received during file upload using #UploadFile

In the REST API below, what is the type of file object that is received.
#Post('/:folderId/documents/:fileName')
#UseInterceptors(FileInterceptor('file'))
#ApiConsumes('multipart/form-data')
#ApiImplicitParam({ name: 'folderId', description: ' Folder Id' })
#ApiImplicitParam({ name: 'fileName', description: ' File Name' })
#ApiImplicitFile({ name: 'file', required: true, description: 'PDF File' })
async uploadFile(#UploadedFile() file, #Param() folderId, #Param() fileName) {
/**
* I need to know the type of file object (first argument) of uploadFile
*/
this.folderService.uploadFile(file, folderId, fileName);
}
I need to write a file received in the request to disk. How to do that?
You can import the type from the package. '#types/multer' and then qualify the file as:
#UploadedFile() file: Express.Multer.File,
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/multer/index.d.ts#L103
You can save the file by specifying a destination path in the MulterOptions:
// files will be saved in the /uploads folder
#UseInterceptors(FileInterceptor('file', {dest: 'uploads'}))
If you want more control over how your file is saved, you can create a multer diskStorage configuration object instead:
import { diskStorage } from 'multer';
export const myStorage = diskStorage({
// Specify where to save the file
destination: (req, file, cb) => {
cb(null, 'uploads');
},
// Specify the file name
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname);
},
});
And then pass it to the storage property in your controller.
#UseInterceptors(FileInterceptor('file', {storage: myStorage}))
For more configuration options, see the multer docs.
try this...
#Post(':userid/avatar')
#UseInterceptors(FileInterceptor('file',
{
storage: diskStorage({
destination: './avatars',
filename: (req, file, cb) => {
const randomName = Array(32).fill(null).map(() => (Math.round(Math.random() * 16)).toString(16)).join('')
return cb(null, `${randomName}${extname(file.originalname)}`)
}
})
}
)
)
uploadAvatar(#Param('userid') userId, #UploadedFile() file) {
this.userService.setAvatar(Number(userId), `${this.SERVER_URL}${file.path}`);
}
check this out for more info -
https://www.techiediaries.com/nestjs-upload-serve-static-file/

nodejs multer diskstorage to delete file after saving to disk

I am using multer diskstorage to save a file to disk.
I first save it to the disk and do some operations with the file and then i upload it to remote bucket using another function and lib.
Once the upload is finished, i would like to delete it from the disk.
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')
and here is how i use it:
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!");
})
})
});
how can i use the diskStorage remove function to remove the files in the temp folder?
https://github.com/expressjs/multer/blob/master/storage/disk.js#L54
update:
I have decided to make it modular and put it in another file:
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 };
You don't need to use multer to delete the file and besides _removeFile is a private function that you should not use.
You'd delete the file as you normally would via fs.unlink. So wherever you have access to req.file, you can do the following:
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!")
})
Multer isn't needed. Just use this code.
const fs = require('fs')
const path = './file.txt'
fs.unlink(path, (err) => {
if (err) {
console.error(err)
return
}
//file removed
})
You may also consider using MemoryStorage for this purpose, with this storage the file is never stored in the disk but in memory and is deleted from the memory automatically after execution comes out of controller block, i.e., after you serve the response in most of the cases.
When you will use this storage option, you won't get the fields file.destination, file.path and file.filename, instead you will get a field file.buffer which as name suggests is a buffer, you can convert this buffer to desired format to do operations on and then upload using a stream object.
Most of the popular libraries support streams so you should be able to use stream to upload your file directly, code for converting buffer to stream:
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
This approach would be more efficient as files will be stored in memory which will result in faster access, but it does have a con as mentioned in multer documentation:
WARNING: Uploading very large files, or relatively small files in
large numbers very quickly, can cause your application to run out of
memory when memory storage is used.
To do it truly automatically across all routes I used this strategy :
when the request ends, we delete all the uploaded files (req.files). Before that, if you want to keep the files on the server, you need to save them in another path.
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);
}
});
I have removed directory after file uploaded using fs-extra
const fs = require('fs-extra');
// after you uploaded to bucket
await fs.remove('uploads/abc.png'); // remove upload dir when uploaded bucket

Categories