fs writeFile in a for loop node js - node.js

I need to convert & write each base64 string from an array to a different file by using fs.writeFile but only the last array element is saved. Have a look at my code below :
let receivedData =["iVBORw0KGgoAAAANSUhEUgAABM...", "4AAANiCAYAAACZ8IVOAAAKqGlDQ1BJQ0MgU..."]:
//decode base 64 to buffer
let decodeBase64 = (dataArray) => {
let result = [];
dataArray.forEach((element) => {
result.push(Buffer.from(element, 'base64'));
})
return result; //array
};
let writeFileAsync = (data) => {
let filename = Date.now() + '.jpeg';
return new Promise((resolve, reject) => {
data.forEach((value) => {
fs.writeFile(filename, value, (err) => {
if(err){
reject(err);
} else {
console.log('file is saved');
resolve(value);
}
})
})
}
let decoded = decodeBase64(receivedData);
writeFileAsync(decoded)
.then((result) => {
console.log('file is saved');
})
.catch((error) => {
console.log(error);
})
the last value of receivedData is saved to filesystem but not the first element
I know it has something to do with doing async method in a loop and maybe something else. The loop just imcrement before writefile finishes.
Any helps/tips would be appreciated thx

Try this, It will upload your file one by one, it will take time but git you the appropriate result:
let fileUpload = async (FILES , PATH, CB)=>{
/** image Path **/
let lengthOfFiles = FILES.length, RETURN_IMAGEPATHS = [], count = 0,
uploadFunc= [];
for(let index= 0; index < lengthOfFiles; index++){
let name = Date.now() + ".png";
RETURN_IMAGEPATHS.push('http://localhost:3000/' + <PATH_FOR_FILE> + name);
uploadImage(<Image save path>, <Imagte file path>, FILES[index]);
}
CB(null, RETURN_IMAGEPATHS);
};
function uploadImage(imageSavePath, filePath, FILE){
return new Promise(async (resolve, reject)=> {
await fs.writeFileSync(imageSavePath, FILE, "base64", function (err) {
if (err)
reject(err);
else {
filePath ='http://localhost:3000/' + filePath;
resolve(filePath);
}
});
})
}
fileUpload(FILES , PATH, (err)=>{
if(err){
console.log(err);
}
else
console.log('Success');
})

Related

Issue when sending multiple images in a GET Method in Nodejs

I am facing issue with sending image in a GET Method in node.js. As you can see in the below code the file is saved in a folder called images and the path of that file is stored in the Object.
I tried searching for the file in the directory and then convert it to base64 to send the images but instead all the files in the directory are being converted to base64 and sent. Hence if you could please help me in resolving this issue.
Please let me know if you require any further information from my end.
Router.js
router.get("/users/data/expand/:nid", async (req, res) => {
var idselected = req.params.nid;
var dir = "images";
try {
const checkData = await user.findOne({ user_id: idselected });
let receivedFile = await Promise.all(
checkData.attachments.flatMap(async element => {
let files = await readDirectory(dir);
return await Promise.all(
files.map(filename => {
filename = element;
return readFile(filename)
})
);
})
);
const returnUser = new User({
user_id: checkData.user_id,
attachments: receivedFile
});
let savedUser = await returnUser.save();
res.status(201).send(savedUser);
} catch (e) {
res.status(500).send(e);
}
});
function readDirectory(dir) {
return new Promise((res, rej) => {
fs.readdir(dir, function(err, files) {
if (err) {
rej(err);
} else {
res(files);
}
});
});
}
function readFile(filename) {
return new Promise((res, rej) => {
fs.readFile(filename, "base64", (err, base64Data) => {
if (err) {
rej(err);
}
res(base64Data);
});
});
}

how to send response only after mv library on nodejs completes. Wrapping in promise doesn't work

I'm trying to setup an endpoint that takes a file through a multipart post request, and saves it into a specific directory using formidable and https://github.com/andrewrk/node-mv. And then upon completion of saving all of the files, I want to respond with a list of all of the files in that directory for rendering. the thing is the response seems to be sent before the directory listing is updated. I tried wrapping the mv operations into a promise and then responding in a then block to no avail. Any help would be much appreciated!
app.post("/api/v1/vendor/:id/menu", (req, res, next) => {
const id = req.params.id;
const form = formidable({ multiples: true, keepExtensions: true });
form.parse(req, (err, fields, files) => {
if (err) {
next(err);
return;
}
if (!Array.isArray(files.image)) {
files = [files.image];
}
let filelist;
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});
Promise.all(proms).then(() => {
console.log('now reading dir...');
filelist = fs.readdirSync("pics/" + id);
res.send(filelist);
});
});
});
I think we're missing the return keywork before new Promise. You can check the proms variable if it contains the list of promises or not.
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});
For me, it should be :
const proms = files.map((file) => {
const dst = `pics/${id}/${file.name}`;
return new Promise((resolve, reject) => {
mv(file.path, dst, { mkdirp: true }, (err) => {
if (err) {
console.error("error: ", err.status);
reject(err);
}
console.log("done moving");
resolve();
});
});
});

How to return a Promise of an array in typescript

I'm trying to return an array in a form of promise. I first unzipped a file, then parsed the file with csv-parse. I'm saving all returned objects in an array, then return this array
I tried to return without a promise the transpiler didn't complain. But I want to scale it
/**
* Wraps writeFile in a promise.
* #param content The Base64 content of the file to read.
* #returns A buffer containing the contents of the file.
*/
protected writeFileAsync(path: string, content: Buffer): Promise<IProblem[]> {
new Promise<Buffer>((resolve, reject) => {
fs.writeFile(path, content, "base64", (err) => {
if (err) {
reject(err);
}
resolve(content);
});
})
.then(result => {
fs.readFile(result, (err, data) => {
if (err) {
Log.error("Error while reading the zip file");
this.listOfProblems = [];
return this.listOfProblems;
}
let zip: JSZip = new JSZip();
zip.loadAsync(data)
.then(contents => {
Object.keys(contents.files).forEach(filename => {
zip.file(filename).async('nodebuffer')
.then(content => {
let parser: csvParse.Parser = csvParse((data, err) => {
if (err) {
Log.error("Error while reading the zip file");
this.listOfProblems = [];
return this.listOfProblems;
}
let problem: IProblem;
}) as csvParse.Parser;
fs.createReadStream(content).pipe(parser);
})
})
})
})
})
.catch(() => {
Log.error("Error while reading the zip file");
this.listOfProblems = [];
return this.listOfProblems;
});
return this.listOfProblems;
}
It's showing error in the last line
You have to return your promise and not the list.
return new Promise<Buffer>((resolve, reject) => {

Bluebird promise, promise.each only executes once

There is a function called musicPromise(). What this function does is
It gets all mp4 files and loop through it.
then it tries to convert each mp4 to mp3, using fluent-ffmpeg
The problem I am facing is
It only converts 1 file, no matter how many mp4 files I have.
And it seems never reach to proc.on('end', (x) => {
Full code here:
// search
const glob = require('glob');
// wait for
const Promise = require('bluebird');
// fs
const fs = require('fs');
// mp3
const ffmpeg = require('fluent-ffmpeg');
// video source file path
const videoPath = '/home/kenpeter/Videos/4K\ Video\ Downloader';
// audio source file path
const audioPath = __dirname + "/audio";
// child process, exec
const exec = require('child_process').exec;
// now rename promise
function renamePromise() { return new Promise((resolve, reject) => {
glob(videoPath + "/**/*.mp4", (er, files) => {
Promise.each(files, (singleClipFile) => {
return new Promise((resolve1, reject1) => {
let arr = singleClipFile.split("/");
let lastElement = arr[arr.length - 1];
let tmpFileName = lastElement.replace(/[&\/\\#,+()$~%'":*?<>{}\ ]/g, "_");
let tmpFullFile = videoPath + "/"+ tmpFileName;
// rename it
fs.rename(singleClipFile, tmpFullFile, function(err) {
if ( err ) console.log('ERROR: ' + err);
console.log("-- Rename one file --");
console.log(tmpFullFile);
resolve1();
}); // end rename
});
})
.then(() => {
console.log('--- rename all files done ---');
resolve();
});
});
}); // end promise
};
// music promise
function musicPromise() { new Promise((resolve, reject) => {
glob(videoPath + "/**/*.mp4", (er, files) => {
Promise.each(files, (singleClipFile) => {
return new Promise((resolve1, reject1) => {
// test
console.log('-- music promise --');
console.log(singleClipFile);
// split
let arr = singleClipFile.split("/");
// e.g. xxxx.mp4
let clipFile = arr[arr.length - 1];
// e.g. xxxx no mp4
let fileName = clipFile.replace(/\.[^/.]+$/, "");
// music file name
let musicFile = fileName + '.mp3';
// set source
let proc = new ffmpeg({source: singleClipFile});
// set ffmpeg path
proc.setFfmpegPath('/usr/bin/ffmpeg');
// save mp3
proc.output("./audio/" + musicFile);
// proc on error
proc.on('error', (err) => {
console.log(err);
});
// done mp3 conversion
proc.on('end', (x) => {
console.log("single mp3 done!");
console.log(x);
// it is resolve1..............
resolve1();
});
// Run !!!!!!!!!!!!!
proc.run();
});
})
.then(() => {
console.log('--------- all mp3 conversion done --------');
resolve();
});
}); // end glob
});
};
// adb kill
function adbKillPromise() { return new Promise((resolve, reject) => {
exec("adb kill-server", (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
console.log('---adb kill---');
resolve();
});
});
};
// adb start
function adbStartPromise() { return new Promise((resolve, reject) => {
exec("adb start-server", (err, stdout, stderr) => {
if (err) {
console.error(err);
return;
}
console.log(stdout);
console.log('---adb start---');
resolve();
});
});
};
// adb push promise
function adbPushPromise() { return new Promise((resolve, reject) => {
glob(audioPath + "/**/*.mp3", (er, files) => {
Promise.each(files, (singleMusicFile) => {
return new Promise((resolve1, reject1) => {
let cmd = "adb push" + " " + singleMusicFile + " " + "/sdcard/Music";
exec(cmd, (err, stdout, stderr) => {
console.log(cmd);
resolve1();
});
});
})
.then(() => {
console.log('---- done push all music ---');
resolve();
});
});
});
};
// Run !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
renamePromise()
.then(musicPromise)
.then(adbKillPromise)
.then(adbStartPromise)
.then(adbPushPromise)
.then(() => {
console.log('---- all done----');
process.exit(0);
})
.catch(err => {
console.log('Error', err);
process.exit(1);
});
A very stupid mistake
function musicPromise() { new Promise((resolve, reject) => {
should be
function musicPromise() { return new Promise((resolve, reject) => {

Move file in Nodejs if file exists otherwise create file

I am trying to move a file from a location abc to location xyz if the file already exists in location xyz delete it then save the new one.
Here is my code
const promises = {
deleteFile: path => {
return new Promise((resolve, reject) => {
const fs = require('fs');
fs.stat(path, (err, stat) => {
if (err === null) {
fs.unlink(path, err => {
if (err) { return reject(err) }
resolve();
})
} else if(err.code == 'ENOENT') {
console.log('File does not exist');
resolve();
} else {
reject(err);
}
});
});
},
copyFile: (from, to) => {
return new Promise((resolve, reject)=> {
copyFile(from, to, (err) => {
if (err) { return reject(err); }
console.log(`Finished writing file ${to}`);
resolve();
})
})
}
}
const copyFile = (from, to, overallCb) => {
const fs = require('fs');
const rs = fs.createReadStream(from)
const ws = fs.createWriteStream(to)
let cbCalled = false;
function done (err) {
overallCb(err);
cbCalled = true;
}
rs.on('error', (err) => {
done(err);
})
ws.on('error', (err) => {
done(err);
})
rs.pipe(ws);
}
;
const OUTPUT_PATH = `./js/libs/`
, _NODE_MODULES = './node_modules/'
, filePath = `${_NODE_MODULES}somePathToAFile`
;
promises.deleteFile(`${OUTPUT_PATH}someFile.min.js`)
.then(promises.copyFile(filePath, `${OUTPUT_PATH}someFile.min.js`))
.then(words => {
console.log('**** done doing things ****');
})
.catch(error => { console.log(`ERROR`, error); })
If the file exists it just simply deletes the file and does nothing else.
If the file DOES NOT exist everything works fine.
Any idea on what im doing wrong?
I had some promise errors in my code... For future me here is the working version of the above code
'use strict';
const promises = {
deleteFile: path => {
return new Promise((resolve, reject) => {
const fs = require('fs');
fs.stat(path, (err, stat) => {
if (err === null) {
fs.unlink(path, err => {
if (err) { return reject(err) }
resolve(`Removing document at ${path}`);
})
} else if(err.code === 'ENOENT') {
resolve('File does not exist');
} else {
reject(err);
}
});
});
},
copyFile: (from, to) => {
return new Promise((resolve, reject) => {
copyFile(from, to, (err) => {
if (err) { return reject(err); }
resolve(`Finished writing file ${to}`);
})
})
}
}
const copyFile = (from, to, overallCb) => {
const fs = require('fs');
const rs = fs.createReadStream(from)
const ws = fs.createWriteStream(to)
let cbCalled = false;
function done (err) {
overallCb(err);
cbCalled = true;
}
rs.on('error', done)
ws.on('error', done)
.on('close', done)
rs.pipe(ws);
}
;
const OUTPUT_PATH = './js/libs/'
, _NODE_MODULES = './node_modules/'
, filePath = `${_NODE_MODULES}somePathToAFile`
;
promises.deleteFile(`${OUTPUT_PATH}someFile.min.js`)
.then(msg => {
console.log(msg)
return promises.copyFile(filePath, `${OUTPUT_PATH}someFile.js`)
})
.then(msg => {
console.log(msg)
})
.catch(err => { // Do errory things}

Resources