Get data from fs.readFile [duplicate] - javascript

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 days ago.
var content;
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
console.log(content);
Logs undefined, why?

To elaborate on what #Raynos said, the function you have defined is an asynchronous callback. It doesn't execute right away, rather it executes when the file loading has completed. When you call readFile, control is returned immediately and the next line of code is executed. So when you call console.log, your callback has not yet been invoked, and this content has not yet been set. Welcome to asynchronous programming.
Example approaches
const fs = require('fs');
// First I want to read the file
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
const content = data;
// Invoke the next step here however you like
console.log(content); // Put all of the code here (not the best solution)
processFile(content); // Or put the next step in a function and invoke it
});
function processFile(content) {
console.log(content);
}
Or better yet, as Raynos example shows, wrap your call in a function and pass in your own callbacks. (Apparently this is better practice) I think getting into the habit of wrapping your async calls in function that takes a callback will save you a lot of trouble and messy code.
function doSomething (callback) {
// any async callback invokes callback with response
}
doSomething (function doSomethingAfter(err, result) {
// process the async result
});

There is actually a Synchronous function for this:
http://nodejs.org/api/fs.html#fs_fs_readfilesync_filename_encoding
Asynchronous
fs.readFile(filename, [encoding], [callback])
Asynchronously reads the entire contents of a file. Example:
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw err;
console.log(data);
});
The callback is passed two arguments (err, data), where data is the contents of the file.
If no encoding is specified, then the raw buffer is returned.
SYNCHRONOUS
fs.readFileSync(filename, [encoding])
Synchronous version of fs.readFile. Returns the contents of the file named filename.
If encoding is specified then this function returns a string. Otherwise it returns a buffer.
var text = fs.readFileSync('test.md','utf8')
console.log (text)

function readContent(callback) {
fs.readFile("./Index.html", function (err, content) {
if (err) return callback(err)
callback(null, content)
})
}
readContent(function (err, content) {
console.log(content)
})

Using Promises with ES7
Asynchronous use with mz/fs
The mz module provides promisified versions of the core node library. Using them is simple. First install the library...
npm install mz
Then...
const fs = require('mz/fs');
fs.readFile('./Index.html').then(contents => console.log(contents))
.catch(err => console.error(err));
Alternatively you can write them in asynchronous functions:
async function myReadfile () {
try {
const file = await fs.readFile('./Index.html');
}
catch (err) { console.error( err ) }
};

This line will work,
const content = fs.readFileSync('./Index.html', 'utf8');
console.log(content);

var data = fs.readFileSync('tmp/reltioconfig.json','utf8');
use this for calling a file synchronously,
without encoding its showing output as a buffer.

As said, fs.readFile is an asynchronous action. It means that when you tell node to read a file, you need to consider that it will take some time, and in the meantime, node continued to run the following code. In your case it's: console.log(content);.
It's like sending some part of your code for a long trip (like reading a big file).
Take a look at the comments that I've written:
var content;
// node, go fetch this file. when you come back, please run this "read" callback function
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
// in the meantime, please continue and run this console.log
console.log(content);
That's why content is still empty when you log it. node has not yet retrieved the file's content.
This could be resolved by moving console.log(content) inside the callback function, right after content = data;. This way you will see the log when node is done reading the file and after content gets a value.

From Node v8
Use the built in promisify library to make these old callback functions more elegant.
const fs = require('fs');
const util = require('util');
const readFile = util.promisify(fs.readFile);
async function doStuff() {
try {
const content = await readFile(filePath, 'utf8');
console.log(content);
} catch (e) {
console.error(e);
}
}
From Node v10
You can use the promises version of fs API:
import { promises as fs } from 'fs';
async function doStuff() {
try {
const content = await fs.readFile(filePath, 'utf8');
console.log(content);
} catch (e) {
console.error(e);
}
}

const fs = require('fs')
function readDemo1(file1) {
return new Promise(function (resolve, reject) {
fs.readFile(file1, 'utf8', function (err, dataDemo1) {
if (err)
reject(err);
else
resolve(dataDemo1);
});
});
}
async function copyFile() {
try {
let dataDemo1 = await readDemo1('url')
dataDemo1 += '\n' + await readDemo1('url')
await writeDemo2(dataDemo1)
console.log(dataDemo1)
} catch (error) {
console.error(error);
}
}
copyFile();
function writeDemo2(dataDemo1) {
return new Promise(function(resolve, reject) {
fs.writeFile('text.txt', dataDemo1, 'utf8', function(err) {
if (err)
reject(err);
else
resolve("Promise Success!");
});
});
}

sync and async file reading way:
//fs module to read file in sync and async way
var fs = require('fs'),
filePath = './sample_files/sample_css.css';
// this for async way
/*fs.readFile(filePath, 'utf8', function (err, data) {
if (err) throw err;
console.log(data);
});*/
//this is sync way
var css = fs.readFileSync(filePath, 'utf8');
console.log(css);
Node Cheat Available at read_file.

var path = "index.html"
const readFileAsync = fs.readFileSync(path, 'utf8');
// console.log(readFileAsync)
using simple readFileSync works for me.

var fs = require('fs');
var path = (process.cwd()+"\\text.txt");
fs.readFile(path , function(err,data)
{
if(err)
console.log(err)
else
console.log(data.toString());
});

var content;
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
console.log(content);
This is just because node is asynchronous and it will not wait for the read function and as soon as the program starts it will console the value as undefined, Which is actually true because there is no value assigned to content variable.
To handle we can use promises, generators etc.
We can use promise in this way.
new Promise((resolve,reject)=>{
fs.readFile('./index.html','utf-8',(err, data)=>{
if (err) {
reject(err); // in the case of error, control flow goes to the catch block with the error occured.
}
else{
resolve(data); // in the case of success, control flow goes to the then block with the content of the file.
}
});
})
.then((data)=>{
console.log(data); // use your content of the file here (in this then).
})
.catch((err)=>{
throw err; // handle error here.
})

The following is function would work for async wrap or promise then chains
const readFileAsync = async (path) => fs.readFileSync(path, 'utf8');

you can read file by
var readMyFile = function(path, cb) {
fs.readFile(path, 'utf8', function(err, content) {
if (err) return cb(err, null);
cb(null, content);
});
};
Adding on you can write to file,
var createMyFile = (path, data, cb) => {
fs.writeFile(path, data, function(err) {
if (err) return console.error(err);
cb();
});
};
and even chain it together
var readFileAndConvertToSentence = function(path, callback) {
readMyFile(path, function(err, content) {
if (err) {
callback(err, null);
} else {
var sentence = content.split('\n').join(' ');
callback(null, sentence);
}
});
};

To put it roughly, you're dealing with node.js which is asynchronous in nature.
When we talk about async, we're talking about doing or processing info or data while dealing with something else. It is not synonymous to parallel, please be reminded.
Your code:
var content;
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
console.log(content);
With your sample, it basically does the console.log part first, thus the variable 'content' being undefined.
If you really want the output, do something like this instead:
var content;
fs.readFile('./Index.html', function read(err, data) {
if (err) {
throw err;
}
content = data;
console.log(content);
});
This is asynchronous. It will be hard to get used to but, it is what it is.
Again, this is a rough but fast explanation of what async is.

I like using fs-extra because all functions are promisified, right out of the box, so you can use await. So your code could look like this:
(async () => {
try {
const content = await fs.readFile('./Index.html');
console.log(content);
} catch (err) {
console.error(err);
}
})();

Related

Refactoring Complicated Nested Node.js Function

I have the following snippet of code below. It currently works, but I'm hoping to optimize/refactor it a bit.
Basically, it fetches JSON data, extracts the urls for a number of PDFs from the response, and then downloads those PDFs into a folder.
I'm hoping to refactor this code in order to process the PDFs once they are all downloaded. Currently, I'm not sure how to do that. There are a lot of nested asynchronous functions going on.
How might I refactor this to allow me to tack on another .then call before my error handler, so that I can then process the PDFs that are downloaded?
const axios = require("axios");
const moment = require("moment");
const fs = require("fs");
const download = require("download");
const mkdirp = require("mkdirp"); // Makes nested files...
const getDirName = require("path").dirname; // Current directory name...
const today = moment().format("YYYY-MM-DD");
function writeFile(path, contents, cb){
mkdirp(getDirName(path), function(err){
if (err) return cb(err)
fs.writeFile(path, contents, cb)
})
};
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
.then((res) => {
res.data.results.forEach((item) => {
download(item.pdf_url).then((data) => {
writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
if(err){
console.log(err);
} else {
console.log("FILE WRITTEN: ", item.pdf_file_name);
}
})
})
})
})
.catch((err) => {
console.log("COULD NOT DOWNLOAD FILES: \n", err);
})
Thanks for any help you all can provide.
P.S. –– When I simply tack on the .then call right now, it fires immediately. This means that my forEach loop is non-blocking? I thought that forEach loops were blocking.
The current forEach will run synchronously, and will not wait for the asynchronous operations to complete. You should use .map instead of forEach so you can map each item to its Promise from download. Then, you can use Promise.all on the resulting array, which will resolve once all downloads are complete:
axios.get(`http://federalregister.gov/api/v1/public-inspection-documents.json?conditions%5Bavailable_on%5D=${today}`)
.then(processResults)
.catch((err) => {
console.log("COULD NOT DOWNLOAD FILES: \n", err);
});
function processResults(res) {
const downloadPromises = res.data.results.map((item) => (
download(item.pdf_url).then(data => new Promise((resolve, reject) => {
writeFile(`${__dirname}/${today}/${item.pdf_file_name}`, data, (err) => {
if(err) reject(err);
else resolve(console.log("FILE WRITTEN: ", item.pdf_file_name));
});
}))
));
return Promise.all(downloadPromises)
.then(() => {
console.log('all done');
});
}
If you wanted to essentially block the function on each iteration, you would want to use an async function in combination with await instead.

callback of the callback function node js

So in Node we use async functions. And to do that we use callback functions as parameters. But how do I execute the final function after which I want to terminate the code? Just pass the empty function? Here's example:
fs.mkdir('stuff', function(){
fs.readFile('readMe.txt', 'utf8', function(err, data) {
fs.writeFile('./stuff/writeMe.txt', data);
});
});
mkdir has callback function - all fine
readFile has callback function - all fine
writeFile has NOT callback function because that's the last thing I want to do, but then I get an error in console:
"DeprecationWarning: Calling an asynchronous function without callback is deprecated."
Should I every time I do that, pass an empty function as a callback to avoid the error? What's the best practice for this?
Should I every time I do that, pass an empty function as a callback to avoid the error?
No.
What's the best practice for this?
Pass in a function and handle any errors it reports. You also need to handle errors from mkdir and readFile, which currently you're ignoring.
E.g.:
fs.mkdir('stuff', function(err) {
if (err) {
// Do something with the fact mkdir failed
} else {
fs.readFile('readMe.txt', 'utf8', function(err, data) {
if (err) {
// Do something with the fact readFile failed
} else {
fs.writeFile('./stuff/writeMe.txt', data, function(err) {
if (err) {
// Do something with the fact writeFile failed
}
});
}
});
}
});
...which is a fair example of callback hell, which is part of the motivation of using promises instead. You could promisify the fs API (using any of several libs, such as promisify) and do it like this:
fsp.mkdir('stuff')
.then(() => fsp.readFile('readMe.txt', 'utf8'))
.then(data => fsp.writeFile('./stuff/writeMe.txt', data))
.catch(err => {
// Do something with the fact something failed
});
...where fsp is a placeholder for the promisified fs API.
In Node 8.x+, you could use async/await to write synchronous-looking code with those promisified APIs:
// This must be inside an `async` function
try {
fsp.mkdir('stuff');
const data = await fsp.readFile('readMe.txt', 'utf8');
await fsp.writeFile('./stuff/writeMe.txt', data);
} catch (err) {
// Do something with the fact something failed
}
You can use writeFileSync instead.
fs.mkdir('stuff', function(){
fs.readFile('readMe.txt', 'utf8', function(err, data) {
fs.writeFileSync('./stuff/writeMe.txt', data);
});
});

Understanding when to use Events and when to use Callback

With events, the initiator raises an event that will be received by those routines that have elected to receive that event. The receiver specifies what events it will receive from what initiators.
With callbacks, the routine after completion notifies the caller of the completion.
So I am confused where should I use events or where should I use the callbacks as I can accomplish what a callback do with events but resulting in a lot of events created in the application.
What should be a good approach to follow while coding, to use events or callbacks?
Events - for things that can happen many times.
Callbacks (or promises) - for things that can happen once.
So for example, when you have a function that you call because you need a current temperature taken from some API, that function should either return a promise or take a callback that can later be called with the right value (or error).
If, on the other hand, you have a function that you call because you need to get a new temperature every time when it changes, then this function should return an event emitter (or take an event handler to attach to some internal event emitter).
Now, the question on when to use callbacks and when to use promises is a little bit more tricky because they are good for the same kinds of situations - when you want to know a result of some asynchronous operation (some data or error). Since both work for the same situations let's consider two examples of reading the contents of a file.
First, with callbacks:
let fs = require('fs');
fs.readFile('a.txt', 'utf-8', (err, data) => {
if (err) {
console.log('Error:', err.message);
} else {
console.log('Data:', data.trim());
}
});
If there is no file it will print:
Error: ENOENT: no such file or directory, open 'a.txt'
If there is a file it will print:
Data: Contents of a.txt
Now, the same with promises:
let fs = require('mz/fs');
fs.readFile('b.txt', 'utf-8')
.then(data => {
console.log('Data:', data.trim());
})
.catch(err => {
console.log('Error:', err.message);
});
It works exactly the same as the previous example.
For that simple example the difference may not be very obvious but what if you wanted to have a function that abstracts some of that logic away.
For example this, with callbacks:
let fs = require('fs');
function a(cb) {
fs.readFile('b.txt', 'utf-8', (err, data) => {
if (err) {
return cb('a() error: ' + err.message);
}
cb(null, 'a() data: ' + data.trim());
});
}
a((err, data) => {
if (err) {
console.log('Error:', err);
} else {
console.log('Data:', data);
}
});
It will print either this
Error: a() error: ENOENT: no such file or directory, open 'a.txt'
or something like this:
Data: a() data: Contents of a.txt
Now, what is different with promises is that you can store it in a variable, return it from a function or pass it as an argument to some other function before attaching the success/error handlers. For example:
let fs = require('mz/fs');
function a() {
return fs.readFile('a.txt', 'utf-8')
.then(data => 'a() data: ' + data.trim())
.catch(err => Promise.reject('a() error: ' + err.message));
}
let promise = a();
promise.then(data => console.log('Data:', data))
.catch(err => console.log('Error:', err));
It works the same, it is written in a different style that you may or may not find more readable, but the difference is that now you don't have to attach a callback at the time of calling the a() function. You can do it somewhere else.
If you didn't want to change the error message, it would be this with callbacks:
function a(cb) {
fs.readFile('a.txt', 'utf-8', (err, data) => {
if (err) {
return cb(err);
}
cb(null, 'a() data: ' + data.trim());
});
and this with promises:
function a() {
return fs.readFile('a.txt', 'utf-8')
.then(data => 'a() data: ' + data.trim());
}
Another difference is that if you have a function that returns a promise, you can use a new await keyword inside of a async function like this:
async function x() {
try {
console.log('Data:', await a());
} catch (err) {
console.log('Error:', err);
}
}
You cannot use await with a function that doesn't return a promise.
It gets very convenient for example when you need to read file a.txt to get another filename that it contains, and then read that other file and print its contents while handling all errors in more complex situations.
To use async and await with Node v7.x you need to use the --harmony flag, see:
http://node.green/#async-functions

AutobahnJS: Remote call to asyncronous function

I'm trying to make a call over WAMP to a remote function. But I don't know how to write the called function if it has asynchronous behavior. In every example I've seen the remote function returns the result. How can this be done in an asynchronous manner where I would normally use a callback?
Example:
This is the registration of a function that would get the contents of a file asynchronously.
session.register('com.example.getFileContents', getFileContents).then(
function (reg) {
console.log("procedure getFileContents() registered");
},
function (err) {
console.log("failed to register procedure: " + err);
}
);
Here is how I would call that function remotely.
session.call('com.example.getFileContents', ["someFile.txt"]).then(
function (res) {
console.log("File Contents:", res);
},
function (err) {
console.log("Error getting file contents:", err);
}
);
But here is the actual function that was registered.
function getFileContents(file) {
fs.readFile(file, 'utf8', function(err, data) {
// How do I return the data?
});
}
How do I return the data from getFileContents so that it can be sent back over the WAMP connection? I know I could use readFileSync and return what it returns. But I'm specifically asking how to do this in an asynchronous manner.
I figured out how to do this with promises. Here is how the function implemented with promises.
var fs = require('fs');
var when = require('when');
function getFileContents(file) {
var d = when.defer();
fs.readFile(file, 'utf8', function(err, data) {
d.resolve(data);
});
return d.promise;
}

Node.js how to read a file and then write the same file with two separate functions?

What I want to do is read a file and then be able to perform other operations with that information as I write the file. For example:
read file
write file and at the same time perform MD5 hash, digital signing etc.
I could use fs.readfile and fs.writefile as one operation and just copy the file from the web server to my computer, but I don't think I could still do these same operations. Anyway, skipping the in between stuff. How do I use fs.readfile and writefile to create two separate functions to copy a file? Here is what I have been working on, and yes I've read these forums extensively in search of an answer.
var fs = require('fs');
function getData(srcPath) {
fs.readFile(srcPath, 'utf8', function (err, data) {
if (err) throw err;
return data;
}
);
}
function writeData(savPath, srcPath) {
fs.writeFile (savPath, (getData(srcPath)), function(err) {
if (err) throw err;
console.log('complete');
}
);
}
//getData ('./test/test.txt');
writeData ('./test/test1.txt','./test/test.txt');
I want to be able to download files of any type and just make raw copies, with md5 hash etc attached to a JSON file. That will probably be a question for later though.
As suggested by dandavis in his comment, readFile does nothing because it is an asynchronous call. Check out this answer for additional information on what that means.
In short, an async call will never wait for the result to return. In your example, getData does not wait for readFile() to return the result you want, but will finish right away. Async calls are usually handled by passing callbacks, which is the last parameter to readFile and writeFile.
In any case, there are two ways to do this:
1.Do it asynchronously (which is the proper way):
function copyData(savPath, srcPath) {
fs.readFile(srcPath, 'utf8', function (err, data) {
if (err) throw err;
//Do your processing, MD5, send a satellite to the moon, etc.
fs.writeFile (savPath, data, function(err) {
if (err) throw err;
console.log('complete');
});
});
}
2.Do it synchronously. Your code won't have to change much, you will just need to replace readFile and writeFile by readFileSync and writeFileSync respectively. Warning: using this method is not only against best practises, but defies the very purpose of using nodejs (unless of course you have a very legitimate reason).
Edit: As per OP's request, here is one possible way to separate the two methods, e.g., using callbacks:
function getFileContent(srcPath, callback) {
fs.readFile(srcPath, 'utf8', function (err, data) {
if (err) throw err;
callback(data);
}
);
}
function copyFileContent(savPath, srcPath) {
getFileContent(srcPath, function(data) {
fs.writeFile (savPath, data, function(err) {
if (err) throw err;
console.log('complete');
});
});
}
This way, you are separating the read part (in getFileContent) from the copy part.
I had to use this recently, so I converted verybadallocs answer to promises.
function readFile (srcPath) {
return new Promise(function (resolve, reject) {
fs.readFile(srcPath, 'utf8', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data)
}
})
})
}
function writeFile (savPath, data) {
return new Promise(function (resolve, reject) {
fs.writeFile(savPath, data, function (err) {
if (err) {
reject(err)
} else {
resolve()
}
})
})
}
Then using them is simple.
readFile('path').then(function (results) {
results += ' test manipulation'
return writeFile('path', results)
}).then(function () {
//done writing file, can do other things
})
Usage for async/await
const results = await readFile('path')
results += ' test manipulation'
await writeFile('path', results)
// done writing file, can do other things
To read and write a file with Non-blocking or Asynchronous way, you can use the advance features of es6 or higher like Promise or Async/await, but you must keep eye on Polyfills (https://javascript.info/polyfills) or if there are only a couple of read/write you can use call back Hell.
function readFiles(){
fs.readFile('./txt/start.txt', 'utf-8', (err, data1)=>{
if(err) return console.log(err);
fs.readFile(`./txt/${data1}.txt`, 'utf-8', (err, data2)=>{
if(err) return console.log(err);
fs.readFile('./txt/append.txt', 'utf-8', (err, data3)=>{
if(err) return console.log(err);
writeFile('./txt/final.txt', `${data2}\n${data3}`);
});
});
});
}
function writeFile(path, data){
fs.writeFile(path,data,'utf-8',err=>{
if(err){
console.log(err);
}
})
}
readFiles();

Categories