Reputation: 69
I trying make read file parameters. When I make this code:
var fs = require('fs'),
size = new Object();
fs.stat(file, function(err,stats){
if(!err){
size=stats;
}
})
console.log(size);
It`s ok, when i trying use function:
var fs = require('fs'),
size = new Object();
function writeinfile(file){
fs.stat(file, function(err,stats){
if(!err){
size=stats;
}
})
console.log(size.size);
}
writeinfile('error.log');
It`s not work. Could you help me that variant 2 work?
Upvotes: 6
Views: 21466
Reputation: 404
You need to put the console.log(size.size); inside the callback function, but i think i need explain better.
You need to learn about asynchronous calls and the Node.js Event Loop. Node.js was created to paralelize resources in a better way that creating threads for problems that are more IO Intensive (like web servers) than CPU Intensive. The idea is that a single thread for the logic with non-blocking calls to use IO is better than create multiple threads and call blocks function to use IO.
If you program in another language, you should be familiar with the sinchronous version of your algorithm:
var fs = require('fs'),
size = new Object();
function writeinfile(file) {
var stats = fs.statSync(path);
size = stats.size;
console.log(size);
};
writeinfile('error.log');
This is Node.js code, but this isn't the Node way. When you call statSync(), your script block to wait for read the stats from the disk.
BUT, when you use just fs.stat()
, your program will run until the end of code, WHILE the disk is reading. All the next lines will be run before the program achieve the Event Loop. Just when the stat be ready and the program run until the end, the event loop will call the callback function that you pass by argument in fs.stat(callback)
call.
So, in your code, you call a stat (assynchronous version), and try use a value that isn't ready yet, because the code after the assynchronous calls always will be run before callback be called.
The first version I think work just because you should be typping the code manually in the interpreter, so, the time you need to type the next line is enought to the program achieve the event loop. In this mode, each time that you type a command, press enter and that code is run, that is, you get a return, the events in event loop will be called after.
Upvotes: 1
Reputation: 17357
In your example, it is not correct to expect the value of size to be set when console.log(size) runs because of the asynchronous nature of fs.stat().
Here's what actually occurs, in order:
fs
module and instantiate a new size
object. Things happen in this order because the amount of time it takes to make the required file system call cannot be predicted beforehand due to the asynchronous nature of file io. Depending on what the disc is currently doing, it could take anywhere from 4 to 4000ms, or more.
This is why we rely on callbacks because they are guaranteed to occur when the function they have been applied to is complete, or in this case, when the status of the filepath has been determined.
And please don't feel bad. This is the one mistake everyone makes when programming asynchronously and it is the hardest concept to wrap one's head around when programming node.
Upvotes: 1
Reputation: 19918
Your console.log is outside your fs.stat callback. Fixed it:
var fs = require('fs'),
size = new Object();
function writeinfile(file){
fs.stat(file, function(err,stats){
if(!err){
size=stats;
console.log(size.size);
}
})
}
writeinfile('error.log');
I've also rewritten your code to use more idiomatic (more common) syntax in Node.js:
var fs = require('fs');
function writeinfile (file, cb) {
fs.stat(file, function(err,stats){
if(err) return cb(err);
cb(null, stats.size);
})
}
writeinfile('error.log', function(err, size) {
if(err) {
console.log(err);
return;
}
console.log('The size of the file is ' + size);
});
As Herman mentioned in his answer, it would be a good idea to choose a better function name if you are not writing to a file.
Last thing, in Javascript, you can use {}
as a shortcut for new Object()
. For example: var size = {};
Upvotes: 12
Reputation: 2769
There are several observations to your code. But we are here to learn:
Make sure to put the console.log
inside the callback (i.e. just below size=stats
), that way you can get the information you need, after the function does its task.
Add this line above if (!err)
:
if (err) console.log(err);
You will see the following
{ [Error: ENOENT, stat 'error.log'] errno: 34, code: 'ENOENT', path: 'error.log' }
That means an error on path. Easy fix: Use fs.exists() to check if the file exists, and / or, always make sure to prefix your filename with __dirname
.
writeinfile
, but fs.stats
gives you information on the file... I suggest that a better function would be fs.write() for this task.Upvotes: 0