Ask coding questions

← Back to all posts
1
nodejs Get random line from file
mwilki7 (111)

How do I get the contents of a text file to an array in nodejs?
Here is my repl: https://repl.it/@mwilki7/nodejstest
I'm trying to open a file, save the array into a global variable to use it later.

I'm using a callback function to proceed after the file is read but these variables

var adjectives = [ ]; 
var nouns = [ ];

show up empty after file reading.

For example,

console.log("First file read");
fs.readFile('adjectives.txt', function(err, data)
{
    if (err) throw err;
    adjectives = data.toString().split("\n");

    console.log(data.toString().split("\n"); // shows normal array
    console.log(adjectives); // shows empty
}, firstPart());

doesn't seem to follow through the assignment synchronously.

I've tried fs.readFileSync(...) but that didn't work either.
Anyone have any ideas how to get random lines in text files with nodejs?

Answered by JustARatherRidi (185) [earned 5 cycles]
View Answer
Commentshotnewtop
1
JustARatherRidi (185)

You're so close!

Basically, You didn't pass in the callbacks the way you were supposed to. Other than that, your code would work just fine.


You'll notice that you have tried to read your first file like this

console.log("First file read");
fs.readFile('adjectives.txt', function(err, data)
{
    if (err) throw err;
    console.log(data)
    adjectives = data.toString().split("\n");
}, firstPart);

First off, you should log the message inside the callback, because only then will you know whether or not the file actually was read. If you log it outside, it will say "First file read" even if it hasn't. Putting it inside, function call looks like:

fs.readFile('adjectives.txt', function(err, data)
{
    if (err) throw err;

    console.log("First file read");

    adjectives = data.toString().split("\n");
}, firstPart);

It is also under the error checking, because if there was an error, then it wouldn't say "First file read".


Now, the problem is with your third argument passed into fs.readFile. There is actually supposed to be only 2 arguments in your case, a file name and a callback. But you've passed it a file name, a callback (an anonymous one), and a third callback (firstPart). So node runs only the firstPart, ignoring the anonymous function in between.

How to fix it? Well, instead of passing a second callback, just call the firstPart function within your first (and only) callback:

fs.readFile('adjectives.txt', function(err, data)
{
    if (err) throw err;

    console.log("First file read");

    adjectives = data.toString().split("\n");

    firstPart();
});

That's it!

Do the same thing for the second readFile as well and you're good to go:

function firstPart()
{
    fs.readFile('nouns.txt', function(err, data)
    {
        if (err) throw err;
        
        console.log("Second file read");
        
        nouns = data.toString().split("\n");

        start();
    });
}

Notice that I'm calling start right away instead of waiting for 5 seconds in the secondPart function. This is because it's no longer needed to wait. All the async functions are called right after the one before, so you don't need to wait for anything to happen.

I've done this and made a couple minor changes, here's the working repl


Hope this helped, let me know if I can clarify anything!

1
mwilki7 (111)

@JustARatherRidi
dag nab this stoopid documentation I mistook
fs.readFile(path[, options], callback)
for three arguments

Thanks for the help, my mind was beginning to melt around this simple operation.

2
JustARatherRidi (185)

@mwilki7 No problem! ^^

Just so you know, that does indeed mean 3 arguments, but not the way you tried to do it.

options usually means an object, with different properties acting like optional keyword arguments. For example my second argument can be { encoding: 'utf8' } to specify that the file is in utf-8.

By the way, the square brackets around , options means that that part is optional :)

1
mwilki7 (111)

One "hack" for this I found was adding a setTimeout for some number of milliseconds

console.log("First file read");
fs.readFile('adjectives.txt', function(err, data)
{
    if (err) throw err;
    adjectives = data.toString().split("\n");
}, firstPart());

function firstPart()
{
    console.log("Second read file");
    fs.readFile('nouns.txt', function(err, data)
    {
        if (err) throw err;
        nouns = data.toString().split("\n");
    }, secondPart());
}
function secondPart()
{
    setTimeout(start, 1000);
}

And now my arrays actually contain stuff.
I won't mark this as an answer, since bigger files may exceed 1000 ms for preparation. I am still open to more robust suggestions.