2

I am new to node.js so bear with me. I need to have a function that returns the line length of a file. I am hoping to do something like

file1 = line_length_func('file');
file2 = line_length_function('file');
if (file1 === file2) { console.log('same number of lines!');}

I have been looking into all sorts of ways to do so, with child.exec(cat file | wc -l) but spawning a child instance gets a bit complicated. I wasn't sure how to pass variables from my child to the parent or if is good practice to do so...

So I tried this - I saw that fd from fs.open returned the number of lines:

function get_lines(file) {
    var lines = fs.open(file, 'r', function(err, fd) {
        var lines = fd;
    });
}

a = get_lines('file.txt');
console.log(a);

but I just get undefined all the time.

The next thing I tried is: (thanks to Andrey Sidorov's post)

function get_line_count(file) {
    var count = 0;
    fs.createReadStream(file)
        .on('data', function(chunk) {
            for (var i = 0; i < chunk.length; i++)
                if (chunk[i] == 10) count++;
        })
        .on('end', function() {
            return count;
        });
}

var file1_lines = get_line_count('test.txt');
console.log(file1_lines);

but I get the same result. Undefined.

I am not used to node yet so any help would be wonderful! Thanks!

update

the line count seems to work now but I still can't write a function that compares the two.

function get_line_count(file, cb) {
    var count = 0;
    fs.createReadStream(file)
        .on('data', function(chunk) {
            for (var i = 0; i < chunk.length; i++)
                if (chunk[i] == 10) count++;
        })
        .on('end', function() {
            cb(null, count);
        })
        .once('error', cb);
}

var file1 = get_line_count('test.txt', function(err, lines) {
    if (err) return; // todo
    return lines;
});

var file2 = get_line_count('test2.txt', function(err, lines) {
    if (err) return; //todo
    return lines;
});

function same_line_length(len1, len2) {
    return len1===len2;
}

console.log(same_line_length(file1, file2));

this is always returning true...

Community
  • 1
  • 1
Ptrkcon
  • 1,455
  • 3
  • 16
  • 32
  • 1
    You should read up on callbacks / asynchronous execution: http://stackoverflow.com/a/4506306/3263412 – marionebl Feb 14 '14 at 02:45
  • Yah, I am not used to how it works. Thanks for the link, I'll check it out while trying to figure this out. Any suggestions for my function? What am I missing? – Ptrkcon Feb 14 '14 at 02:50

3 Answers3

2

Your "get_line_count" is complete before file read operations even started. It's async IO, if that can help consider naming your function "start_file_linecount_sequence(name, oncomplete)" - the function puts some requests in the queue and exits (almost immediately) and your handler is called from event loop at some point of time later.

function get_line_count(file, cb) {
    var count = 0;
    fs.createReadStream(file)
        .on('data', function(chunk) {
            for (var i = 0; i < chunk.length; i++)
                if (chunk[i] == 10) count++;
        })
        .on('end', function() {
            cb(null, count)
        })
        .once('error', cb);
}

get_line_count('test.txt', console.log);
Andrey Sidorov
  • 24,905
  • 4
  • 62
  • 75
  • I have not used .once(event, listener) before. It passes any errors from fs.readstream to my function? – Ptrkcon Feb 14 '14 at 03:07
  • in calls parameter ( callback ) only once - this way only first error is reported. Usual convention for 'error' event is to have one single parameter, usually js Error object – Andrey Sidorov Feb 14 '14 at 03:09
  • Is it always the case that 'error' only has a single parameter? Just curious for future reference. – Ptrkcon Feb 14 '14 at 03:11
  • See http://docs.nodejitsu.com/articles/errors/what-are-the-error-conventions concerning the error convention in node.js @Ptrkcon – marionebl Feb 14 '14 at 03:16
  • 1
    if I try to set get_line_count('test.txt', doSomething()); to a variable, I get undefined again… I'm trying to compare 2 get_line_counts. sigh. – Ptrkcon Feb 14 '14 at 03:44
  • @AndreySidorov Is there any way to return the count, I tried the above but I am also facing the same issue – Mahavir Munot Jan 25 '16 at 11:44
  • "return" in async data flow is often "get as callback function parameter" - just put anonymous function where I have console.log in example and use parameter passed to that function – Andrey Sidorov Jan 27 '16 at 05:46
1

In the function get_line_count(file), return count is for the anonymous function('end' event handler), not for get_line_count(). So calling get_line_count() will return undefined.

Suppose you have a function that needs to know the line count:

function doSomething(count) {
  //your code
}

Change the definition of get_line_count to:

function get_line_count(file, cb) {
  var count = 0;
  fs.createReadStream(file)
    .on('data', function(chunk) {
        for (var i = 0; i < chunk.length; i++)
            if (chunk[i] == 10) count++;
    })
    .on('end', function() {
        // return count;
        cb(count);
    });
}

Finally, call get_line_count() like this:

get_line_count(file, doSomething);
bnuhero
  • 2,734
  • 1
  • 19
  • 16
  • How do I return the count variable that is in the function scope? – Ptrkcon Feb 14 '14 at 02:48
  • @Ptrkcon The only way is `fs.readFileSync`, but synchronously I/O is not recommended, since this will block current thread. –  Feb 14 '14 at 02:55
  • see Andrey Sidorov's answer. It's better to add the error argument to the callback function. – bnuhero Feb 14 '14 at 02:56
1

Both functions you tried work with async core methods: fs.createReadStream and fs.open. To get your result from these functions you have to pass a callback in, like this:

function getLineCount(file, cb) {
    var count = 0;

    fs.createReadStream(file)
      .on('data', function(chunk) {
        for (var i = 0; i < chunk.length; i++)
        if (chunk[i] == 10) count++;
      })
      .once('error', cb)
      .on('end', function() {
        cb(null, count);
      });
}


getLineCount('example.txt', function(err, count) {
    if (err) return err; // do something about the error
    console.log(count);
});

More information on closures and callbacks: What are Closures and Callbacks?

Community
  • 1
  • 1
marionebl
  • 3,342
  • 20
  • 34
  • 1
    fs.open returns file descriptor in callback, not file content. Also cb is third parameter (second being 'mode', for example 'r') – Andrey Sidorov Feb 14 '14 at 02:56
  • You're right. Followed the op there without testing it before. Updated to use `fs.createReadStream`, but I see you posted this first @AndreySidorov. – marionebl Feb 14 '14 at 03:07