0

This is my first day in NodeJS and I need to write a small a program that checks for a certain word in a list of files and folders and prints out an array of files that contains this word,

I have written the program but unfortunately i wrote it in a synchronous way, not knowing that NodeJS is asynchronous, after searching the internet I found out the problem but I can't still figure out the solution.

Here is the code that I wrote:

// Get needed arguments for running the script
// USAGE: node search [EXT] [TEXT]
var args = process.argv.slice(2);

if(args[0].length == 0 && args[1].length == 0) { 
    console.log("USAGE: node search [EXT] [TEXT]");
    process.exit();
}

ext_args = args[0];
word_args = args[1];

var fs = require('fs'); // include file reader module
var path = process.cwd(); // get current path of script
var fileList = getFiles(path, ext_args, word_args);
console.log(fileList);
console.log("end");
/*
Function that get files recursively in a current script path
*/
function getFiles(path, ext, word) {
    var fileList = [];
    fs.readdir(path, function(err, items) {
        for (var i=0; i<items.length; i++) {
            var currentFile = items[i];
            var itemPath = path + "\\" + currentFile;
            if(fs.lstatSync(itemPath).isDirectory()) {              
                return getFiles(path + '\\' + currentFile, ext, word);
            } else {
                if(currentFile.endsWith(ext)) {
                   fileList.push(checkString(itemPath, word));
                } else {
                }
            }
        }
    });
    return fileList;
}

/*
 Function that checks if the word exist in the text file
*/
function checkString(filePath, word) {
    fs.readFile(filePath, 'utf8', function(err, data) {
        //console.log("> Checking String");
        if(err) throw err;
        if(data.indexOf(word) >= 0) {           
            return filePath;
        } else {          
        }

    })
}

When I print fileList I get it as an empty array. Can you show me how to write the recursive function in a proper way?

0.sh
  • 2,659
  • 16
  • 37
MuhammadNe
  • 674
  • 4
  • 11
  • 24
  • so what you are trying to do is check if a file with a certain word in its filename, within a directory or subdirectories exists? – George Mar 23 '18 at 20:27
  • `fileList.push(checkString(itemPath, word));` uses an async function which is why its empty – Jankapunkt Mar 23 '18 at 20:27
  • `checkString` needs to use `fs.readFileSync` or you need to redesign all your code to async. – Jankapunkt Mar 23 '18 at 20:28
  • @Noface I want to get a list of all files in directories and directories that contains certain word – MuhammadNe Mar 23 '18 at 20:29
  • @Jankapunkt There is no problem if I redesign the entire code, but the problem is I don't know where how start learning the right async way for recursive functions, but mean while I will check the readFileSync – MuhammadNe Mar 23 '18 at 20:30
  • try searching npm e.g. https://www.npmjs.com/search?q=find%20in%20file or https://www.npmjs.com/search?q=recursive%20directory – George Mar 23 '18 at 20:31
  • 1
    it is unecessary to write this code from scratch when a substantial amount has already been done – George Mar 23 '18 at 20:32
  • @Jankapunkt Also when I start the node program it prints the empty array then it starts getting the files and so on. – MuhammadNe Mar 23 '18 at 20:32
  • @Noface i will check these packages – MuhammadNe Mar 23 '18 at 20:33
  • https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – George Mar 23 '18 at 20:33

1 Answers1

1

You need to use Async/await or promise to handle the asynchronous I/O operation as below:

// Get needed arguemnts for running the script
// USAGE: node search [EXT] [TEXT]
var args = process.argv.slice(2);

if (args[0].length == 0 && args[1].length == 0) {
    console.log("USAGE: node search [EXT] [TEXT]");
    process.exit();
}

ext_args = args[0];
word_args = args[1];

var fs = require('fs'); // include file reader module
var path = process.cwd(); // get current path of script
getFiles(path, ext_args, word_args).then((fileList) => {
    console.log(fileList);
    console.log("end");
});
/*
Function that get files recursivly in a current script path
*/
function getFiles(path, ext, word) {
    var fileList = [];
    return new Promise((resolve, reject) => {
        fs.readdir(path, (err, items) => {
            for (var i = 0; i < items.length; i++) {
                var currentFile = items[i];
                var itemPath = path + "\\" + currentFile;
                if (fs.lstatSync(itemPath).isDirectory()) {
                    resolve(getFiles(path + '\\' + currentFile, ext, word));
                } else {
                    if (currentFile.endsWith(ext)) {
                        fileList.push(checkString(itemPath, word));
                    } else {}
                }
            }
        });
        resolve(fileList);
    })
}

/*
 Function that checks if the word exist in the text file
*/
function checkString(filePath, word) {
    return new Promise((resolve, reject) => {
        fs.readFile(filePath, 'utf8', (err, data) => {
            //console.log("> Checking String");
            if (err) {
                reject(err);
            }
            if (data.indexOf(word) >= 0) {
                resolve(filePath);
            }
        })
    })
}
kgangadhar
  • 4,886
  • 5
  • 36
  • 54
  • what about the line the call getFiles recursivly "return getFiles(path + '\\' + currentFile, ext, word);", is this fine? – MuhammadNe Mar 23 '18 at 20:41
  • need to use resolve like this `resolve(getFiles(path + '\\' + currentFile, ext, word))` – kgangadhar Mar 23 '18 at 20:43
  • Im reading about promise now, I added a console logs to the file "console.log("Start");" inside "function getFiles(path, ext, word) {" but the output is "start [] end start start start start", Im checking how to fix it. – MuhammadNe Mar 23 '18 at 20:47
  • It's hard to tell what's happening as i not sure where u put it, the minute you use promise it'll make sure it waits for the process to execute before sending the response to resolve or reject within the promise block. – kgangadhar Mar 23 '18 at 20:52
  • And you are using recursive code `getFiles(` is calling `getFiles(` again, it hard tell unless u debug your code to understand when the log happened. try some `ide` like `vscode` to debug – kgangadhar Mar 23 '18 at 20:53