What I want to do is to output the content of all the files in a folder:
const fs = require('fs')
, input = process.argv[2]
fs.readdir(__dirname + `/${input}/`, (err, files) => {
if (err) {
console.log(err)
return
}
files.forEach((file) => {
console.log(file)
fs.readFile(file, 'utf8', (err, data) => {
console.log(data)
})
})
})
But I'm puzzled console.log(file) do output the file names:
alex#alex-K43U:~/node/m2n/bin$ node index4.js folder
test.txt
test2.txt
But console.log(data) returns undefined:
alex#alex-K43U:~/node/m2n/bin$ node index4.js folder
undefined
undefined
What's happening here?
EDIT:
Maybe there's a problem with __dirname? This is my project structure:
You need to pass full path to your filenames:
fs.readFile(__dirname + `/${input}/` + file, 'utf8', (err, data) => {
And I would recommend you to log errors so you will know next time what is happening wrong:
fs.readFile(__dirname + `/${input}/` + file, 'utf8', (err, data) => {
if (err) {
console.log(err)
}
console.log(data)
})
Related
I am using json-server custom output to read md file. I want to return the contend on specific rout as text/plain, so I wrote this code:
server.get('/static/*', (req, res) => {
const filePath = path.join(__dirname, `myfile.md`);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.send(err);
return;
}
res.format({
'content-type: text/plain': () => res.send(data),
});
});
});
When I am accessing that route I am getting an error NotAcceptableError: Not Acceptable Any ideas how to fix?
res.format is not what you want to use. You use res.set to set a response header - like so:
server.get('/static/*', (req, res) => {
const filePath = path.join(__dirname, `myfile.md`);
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
res.send(err);
return;
}
res.set('Content-Type', 'text/plain');
res.send(data);
});
});
The following code does not create a new directory, nor does it output any err
const fs = require("fs-extra");
fs.mkdir(dirPath, { recursive: true }, (err) => {
if (err) {
console.log("ERR: When attempting to mkdir", err);
} else {
console.log("MKDIR made " + dirPath);
}
cb(null, dirPath);
});
I would expect the directory to be created... or an error.
When I console.log(err) I find that the value of err is null.
How can I ensure this directory has been created?
I need to remove an image file from my backend, the folder is: /uploads. When i call the function deleteProduct it removes the product from the data base but the image of the product its still in folder.
deleteProduct: (req, res) => {
let productId = req.params.id;
Product.findById(productId, (err, res) =>{
var imageResponse = res.image;
console.log(imageResponse);
});
//console.log(imageResponse);
//fs.unlink('./uploads' + imageResponse );
When i try to access imageResponse outside the findById, console prints: "imageResponse" is not defined. Then i need to delete that file with fs. Im not sure if i wrote correct the unlink function. Thanks in advance.
For fs.unlink
Have you made sure to:
Include fs = require('fs')?
Used __dirname?
Include file extension (.png, .jpg, .jpeg)?
const fs = require('fs');
fs.unlink(__dirname + '/uploads' + imageResponse + ".png", (err) => {
if (err) throw err;
console.log('successfully deleted file');
});
For image response being undefined
You didn't provide information on the Product constructor, but I assume Product.findById is asynchronous. You may need to use an async function
const fs = require('fs');
async function deleteProduct (req, res) => {
let productId = req.params.id;
Product.findById(productId, (err, res) =>{
var imageResponse = res.image;
console.log(imageResponse);
fs.unlink(__dirname + '/uploads' + imageResponse + ".png", (err) => {
if (err) throw err;
console.log('successfully deleted file');
});
});
}
Further reading:
Node File API: https://nodejs.org/api/fs.html
Async functions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Finally it seems to be working, the file succesfully vanished from the folder, im still open for advices, thanks.
deleteProduct: (req, res) => {
let productId = req.params.id;
Product.findById(productId, (err, res) =>{
if(err) return res.status(500).send({message: 'Error'});
fs.unlink('./uploads/' + res.image, (err) => {
if(err) return res.status(500).send({message: 'Error'});
})
});
I am currently trying to read a file using fs in Node v12.16.2. I currently have a function setup like so:
const fs = require('fs');
var JSONData;
const read = function(path){
fs.readFile(path, 'utf8', (data, err) => {
if(err){
console.log(err);
console.log('there was an error');
}
JSONData = data;
})
}
read('./path/to/file.json');
In the console, I simply get
{}
there was an error
I also tried console.loging err.message, err.valueOf, and using throw err, none of which gave me any more data on the error. I'd appreciate if someone could help either discover my problem or knows it already.
Callbacks in Node.js receive the error as the first argument:
const fs = require('fs');
var JSONData;
function read (path) {
fs.readFile(path, 'utf8', (err, data) => { // <-- Look here
if (err) {
console.log(err);
console.log('there was an error');
}
JSONData = data;
})
}
read('./path/to/file.json');
Here's the problem.
I have a global variable(Array type) named folders
let folders = [];
I modify it inside a Callback function inside yet another callback function.
Here's how.
app.get("/", (req, res) => {
// TODO: Proceed only if the path is correct and it is a directory
fs.readdir(dir, (err, files) => {
console.log("READING:");
if (err) throw err;
files.forEach(file => {
const add = folder => folders.push(folder);
fs.lstat(path.join(dir, file), (err, stats) => {
if (err) throw err;
if (stats.isDirectory()) {
add(file);
}
console.log("INSIDE: " + folders);
});
console.log("OUTSITE: " + folders);
});
});
res.send(folders.length.toString());
});
Now the problem is, that when I read it on this line:
res.send(folders.length.toString());
The length is always 0.
And it is also 0 on console log line where I Print it with OUTSITE but it reads fine when I print it on the line where I mention it with INSIDE.
I know the problem after some search. It happens because the callback sets the variable on a later time in the event loop.(If it makes any sense, but you get the point).
I know the problem but I don't have any idea of how to solve it. I have tried various implementations including adding a global function that pushes to the array and calling it frpm inside the callback but the results are same.
Here's the full code.
const express = require("express");
const fs = require("fs");
const path = require("path");
const os = require("os");
// Initialize Express
const app = express();
// PORT on which the app process should be started
const PORT = process.env.PORT || 5100;
// Setting Up the path to Projects folder dynamically
// !Currently only works(tested) on the Darwin(MacOS) systems PS. I don't own a Windows
// TODO: Test on Windowsn and Linux
const homedir = os.homedir();
const dir = `${homedir}/Projects/`;
// TODO: Re-Write using Async/Await as it is not fully suppported as of Node version 10.0
let folders = [];
// Home Route
app.get("/", (req, res) => {
// TODO: Proceed only if the path is correct and it is a directory
fs.readdir(dir, (err, files) => {
console.log("READING:");
if (err) throw err;
files.forEach(file => {
const add = folder => folders.push(folder);
fs.lstat(path.join(dir, file), (err, stats) => {
if (err) throw err;
if (stats.isDirectory()) {
add(file);
}
console.log("INSIDE: " + folders);
});
console.log("OUTSITE: " + folders);
});
});
res.send(folders.length.toString());
});
// Start the express server
app.listen(PORT, err => {
if (err) throw err;
console.log(`Project Lister Running On PORT: ${PORT}`);
});
Any solutions?
The issue here is that fs.lstat is asynchronous.
If you use the sync version fs.lstatSync, then you can call res.send after the forEach loop.
app.get("/", (req, res) => {
// TODO: Proceed only if the path is correct and it is a directory
fs.readdir(dir, (err, files) => {
console.log("READING:");
if (err) throw err;
files.forEach(file => {
const add = folder => folders.push(folder);
try {
const stats = fs.lstatSync(path.join(dir, file))
if (stats.isDirectory()) {
add(file);
}
} catch (err) {
throw err
}
});
res.send(folders.length.toString());
})
})
Or for a non-blocking way you could use Promise.all:
app.get("/", (req, res) => {
// TODO: Proceed only if the path is correct and it is a directory
fs.readdir(dir, (err, files) => {
console.log("READING:");
if (err) throw err;
const promises = files.map(file => {
return new Promise((resolve, reject) => {
fs.lstat(path.join(dir, file), (err, stats) => {
if (err) {
reject(err);
}
if (stats.isDirectory()) {
add(file);
resolve();
}
console.log("INSIDE: " + folders);
});
});
});
Promise.all(promises, () => {
res.send(folders.length.toString());
});
});
});
So, here's the simplest solution I can find on my own!
#PeterN's answer is correct but could be hard to wrap a beginner's head around!
Here's my final code.
const express = require("express");
const fs = require("fs").promises; // !IMPORTANT Get the promises version of the File System Module
const path = require("path");
const os = require("os");
// Initialize Express
const app = express();
// PORT on which the app process should be started
const PORT = process.env.PORT || 5100;
// Setting Up the path to Projects folder dynamically
// !Currently only works(tested) on the Darwin(MacOS) systems PS. I don't own a Windows
// TODO: Test on Windows and Linux
const homedir = os.homedir();
const dir = `${homedir}/Projects/`;
// Home Route
app.get("/", async (req, res) => {
let folders = [];
// TODO: Proceed only if the path is correct and is a directory
try {
let files = await fs.readdir(dir);
for (let i = 0; i < files.length; i++) {
let file = await fs.lstat(path.join(dir, files[i]));
if (file.isDirectory()) {
folders.push(files[i]);
}
}
} catch (error) {
console.error(error);
}
res.send(folders);
});
// Start the express server
app.listen(PORT, err => {
if (err) throw err;
console.log(`Project Lister Running On PORT: ${PORT}`);
});
Take note, on the second line where I am importing the 'fs' modules, I now import it differently or rather say a different version!
I now import it as:
const fs = require("fs").promises;
The '.promises' added at the last imports the functions, methods of that module in their Promise based implementation. Thought you must note that it is stable only in version 11.x and up of NodeJs as of right now. I am using >12.x.
Now the rest of the process is rather straight forward assuming you are familiar with Async/Await and Promises. And if you're not I would highly suggest getting into it as it can save your day as it did with me.
Here's a great tutorial regarding it: Async/Await and Promise in JS
Ps. Use the for loop instead of 'array.forEach(e => //Do Something);' approach as it will again introduce the same problem as faced earlier because it is also callback-based!
Hope I helped you. Thanks!