How do I overwrite a file with the fs module? - javascript

I'm making an electron app for windows. When I try to overwrite a txt file it just deletes everything. I want that but the content I am trying to put is not writing to the file.
Here is the code for when receive a prompt to save:
ipcRenderer.on('saveFile', function(){
console.log(fileData.path)
fs.writeFile(fileData.path, editor.innerText, 'utf8', (err) => {
if(err) throw err;
console.log('File Saved')
})
})
Here is the code when I send the file data (file path, text in file, etc.):
fileBtn.addEventListener('change', function(e){
if(fileBtn.files[0].type.substring(0, 4) == 'text'){
file.ext = fileBtn.files[0].name.substr(fileBtn.files[0].name.indexOf('.'))
console.log(fileBtn.files[0])
file.path = fileBtn.files[0].path
file.text = fs.readFileSync(file.path, 'utf8');
ipcRenderer.send('newFile', file)
}else{
console.error('Not a valid file type')
return;
}
})

Related

How to retrieve a file using node.js fs readFile function without specifying the name?

I'm currently stuck trying to retrieve a file from file system in order to send it through api to the client. For my backend I'm using express js
I'm using fs library and currently I'm trying to do it with readFile function, but I want to do it without specifying the file name or just the file extension because it will depend from file file will be uploaded from client.
What I tried until now (unsuccessfully) is shown below:
router.get("/info/pic", async (req, res) => {
const file = await fs.readFile("./images/profile/me.*", (err, data) => {
if (err) {
console.log(err); // Error: ENOENT: no such file or directory, open './images/profile/me.*'
return;
}
console.log(data);
});
});
const file = await fs.readFile("./images/profile/*.*", (err, data) => {
if (err) {
console.log(err); // Error: ENOENT: no such file or directory, open './images/profile/*.*'
return;
}
console.log(data);
});
const file = await fs.readFile("./images/profile/*", (err, data) => {
if (err) {
console.log(err); // Error: ENOENT: no such file or directory, open './images/profile/*'
return;
}
console.log(data);
});
If I specify the file name everything works fine, like: fs.readFile("./images/profile/me.jpg". but as I said, I don't know for sure the right extension of that file.
Important info: In that directory there will be only one file!
Please help me!
Thank you in advance!
If there is only one file in the directory, the following loop will have only one iteration:
for await (const file of fs.opendirSync("./images/profile")) {
var image = fs.readFileSync("./images/profile/" + file.name);
...
}
const fs = require('fs');
fs.readdir('./images/profile', function (err, files) {
//handling error
if (err) {
return console.log('err);
}
files.forEach(function (file) {
// Do whatever you want to do with the file
});
});

How to delete a file with an unknown extension using fs in NodeJS?

I want to delete a file named myfile with any extension.
const fs = require('fs')
const ext = '' ; //this extension may be anything
const path = './myfile.'+ext ;
fs.unlink(path, (err) => {
if (err) {
console.error(err)
return
}
//file removed
})
The error I get:
no such file or directory named myfile
But there is a file named myfile.jpg which I want to delete. Let's pretend that we don't know the extension. How can I delete it?
unlink doesn't support regex to delete file. You will probably need to loop through the the folder and find the filename start with 'myfile' and delete it accordingly.
const fs = require('fs');
const director = 'path/to/directory/'
fs.readdir(directory, (err, files) => {
files.forEach(file => {
if(file.split('.')[0] == 'myfile') fs.unlink( directory + file );
});
});

Multer NodeJS Extension: Unable to upload an Excel File using Multer

I tried to use multer to upload files onto my server for my NodeJS/Express web application.
I wrote the following function using multer, however, it just displays a page that says [Object Object] and I have no idea why. I am getting no console logs despite inputing them:
This is my route in my controllers: (I have a form that has a file upload tag on one of my pages)
router.post('/upload/file', multer(multConfFile).single('file'), function(req,res){
if (req.fileValidationError) {
console.log("This was a valid error");
return res.send(req.fileValidationError);
}
else if (!req.file) {
console.log("this error occured");
return res.send('Please select a file to upload');
}
else if (err instanceof multer.MulterError) {
console.log("Multer error");
return res.send(err);
}
else{
console.log(req.file)
res.redirect('back');
}
This is my multer config to allow uploads of Excel files:
const multConfFile = {
storage: multer.diskStorage({
destination: function(req,file,callback){
callback(null, '../models/assets/files');
},
filename: function(req, file, callback){
const ext = file.mimetype.split('/')[1];
console.log(ext);
callback(null, file.fieldname + ext);
}
}),
fileFilter: function(req, file, next){
if(!file){
next();
}
if(!file.originalname.match(/\.(xlsx|xlsb|csv|xlsm)$/)){
next(null, true);
}
else{
next({message: "File not supported"});
}
}
};
I am not certain why this is not working? Any suggestions? Could it be a problem with excel file uploads?

Express file upload and view

I am using express-fileupload to upload the images. The images are saved in my local directory. I want to insert the name of the file to the mongodb if possible. Finally I want the image to be displayed in my frontend.
function insertRecord(req,res){
if(req.files){
const file=req.files.filename
filename=file.name
file.mv("./upload"+filename,function(err){
if(err)
console.log(err)
})
}
const user=new User()
user.name=req.body.name
user.address=req.body.address
user.email=req.body.email
user.mobile=req.body.mobile
user.filename=req.body.filename
user.save((err,docs)=>{
if(!err){
res.redirect('/user/list')
}
else {
if (err.name == 'ValidationError') {
handleValidationError(err, req.body);
res.render("./users/addOrEdit", {
viewTitle: "Insert User",
user: req.body
});
}
else
console.log('Error during record insertion : ' + err);
}
});
}
I am not sure whether the way to insert the name of the file to the mongodb is correct or not. Anyway, that is optional but I am not understanding how can I display the uploaded images which are present in the local directory.
I tried to save the image as base64 but the record is not saved to the database now.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
router.post('/',upload.single('myImage'),function(req,res){
if (req.body._id == '')
insertRecord(req, res);
else
updateRecord(req, res);
})
function insertRecord(req,res){
var img = fs.readFileSync(req.file.path);
var encode_image = img.toString('base64');
var finalImg = {
contentType: req.file.mimetype,
image: new Buffer(encode_image, 'base64')
};
const user=new User()
user.name=req.body.name
user.address=req.body.address
user.email=req.body.email
user.mobile=req.body.mobile
user.save(finalImg,(err,docs)=>{
if(!err){
res.redirect('/user/list')
}
else {
if (err.name == 'ValidationError') {
handleValidationError(err, req.body);
res.render("./users/addOrEdit", {
viewTitle: "Insert User",
user: req.body
});
}
else
console.log('Error during record insertion : ' + err);
}
});
}
Edit: I think there is a problem in the code: it should be `'./upload/'+filename' not without the second slash.
In order to show the images, you have to open a static route in Express. Example: app.use('/images', express.static(PATH)). Then you can, in the frontend, call it as <img src="URL/images/FILENAME" />
From your code, it is not possible to understand what kind of data you are sending to the server. As far as I understand, you're trying mv the string filename. In order to transfer files (such as images), you should have form-data instead of JSON data or you should encode the image file into Base64 to transfer it as text (not the filename, the whole file).
Check Multer out for this kind of job. It is described well in the README.md. Apart from that, until you submit the form, the image won't be available in the front-end. If you want to preview the image before uploading it's a separate process which you can learn more in here.

How to detect when user has saved file to local disk in Angular/NodeJS?

I'm creating a temporary JSON file in my NodeJS backend which holds the information the user has filled in a form. At the end of the form when user clicks on the download button, I run some Python script in NodeJS to validate the data and then create a temporary file of this JSON data and return it to user as a HTTP GET response.
Right now I'm using a timer to delete this temporary file after 10 seconds, which is bad. I want to know how to detect when the user has fully downloaded the file to their local disk from the browser so I can delete this temporary file in backend.
The client Angular code:
$scope.downloadForm = function() {
var data = formDataFactory.getDataForSubmission();
var url = '/FormSubmission/DownloadData';
// Below POST call will invoke NodeJS to write the temporary file
$http.post(url, data)
.success(function(data, status) {
$scope.downloadPath = data.filePath;
$scope.downloadFile = data.fileName;
url = '/tmp/forms/' + $scope.downloadFile;
// If the temporary file writing is successful, then I get it with a GET method
$http.get(url)
.success(function(data, status) {
$log.debug("Successfully got download data");
$window.location = $scope.downloadPath;
})
.error(function(data, status) {
$log.error("The get data FAILED");
});
})
.error(function(data, status) {
$log.error("The post data FAILED");
});
}
$scope.download = function() {
$scope.downloadForm();
setTimeout(function() { //BAD idea
$scope.deleteForm($scope.downloadPath);
}, 10000);
}
The server NodeJS code:
// POST method for creating temporary JSON file
router.post('/FormSubmission/DownloadData', function(req, res) {
if (!req.body) return res.sendStatus(400); // Failed to get data, return error
var templateString = formTmpPath + 'form-XXXXXX.json';
var tmpName = tmp.tmpNameSync({template: templateString});
fs.writeFile(tmpName, JSON.stringify(req.body, null, 4), function(err) {
if (err) {
res.sendStatus(400);
} else {
res.json({ fileName: path.basename(tmpName), filePath: tmpName, out: ''});
}
});
});
// Get method for downloading the temporary form JSON file
router.get('/tmp/forms/:file', function(req, res) {
var file = req.params.file;
file = formTmpPath + file;
res.download(file, downloadFileName, function(err) {
if (err) debug("Failed to download file");
});
});
Update:
I'm trying to use a stream now to send the data back, but for some reason this get method is called twice!? Can't understand why!!
// Get method for downloading the temporary form JSON file
router.get('/tmp/forms/:file', function(req, res) {
var filename = "ipMetaData.json";
var file = req.params.file;
file = formTmpPath + file;
var mimetype = mime.lookup(file);
const stats = fs.statSync(file);
res.setHeader('Content-disposition', 'attachment; filename=' + filename);
res.setHeader('Content-type', mimetype);
res.setHeader('Content-Length', stats.size);
console.log("Will send the download response for file: ", file);
//var path = __dirname + "\\..\\tmp\\forms\\form-auSD9X.json";
console.log("Creating read stream for path: " + file);
var stream = fs.createReadStream(file);
// This will wait until we know the readable stream is actually valid before piping
stream.on('open', function () {
// This just pipes the read stream to the response object (which goes to the client)
stream.pipe(res);
});
// This catches any errors that happen while creating the readable stream (usually invalid names)
stream.on('error', function(err) {
console.log("Caught an error in stream"); console.log(err);
res.end(err);
});
stream.on('end', () => {
console.log("Finished streaming");
res.end();
//fs.unlink(file);
});
});
if I understand your problem correctly, you can do this in different ways, but easiest way is first, remove the timer to remove the file, and remove it after the download completes from the backend as follows
router.get('/tmp/forms/:file', function(req, res) {
var file = req.params.file;
file = formTmpPath + file;
res.download(file, downloadFileName, function(err) {
if (err) debug("Failed to download file");
else {
// delete the file
fs.unlink(file,function(err){
if(err) debug(err);
})
}
});
});
The problem was with doing a get call and then change location to the file path which has the same path. I changed my API path and used the stream .on('end', callback) to remove the file.
// If the temporary file writing is successful, then I get it with a GET method
$http.get(url) --> this URL should be different from $window.location
.success(function(data, status) {
$log.debug("Successfully got download data");
$window.location = $scope.downloadPath;
})
.err

Categories

Resources