module IO in nodejs - javascript

I am new to node.js and trying to figure out how to write a module and use it in another file.
This is the module which I wrote to list the files according to the extension of files.
input : directory and extension of file.
module : module_import.js
var fs = require('fs')
var path = require('path')
module.exports = function (dir, filterStr, callback) {
fs.readdir(dir, function (err, list) {
if (err) {
return callback(err)
}
list = list.filter(function (file) {
return path.extname(file) === '.' + filterStr
})
callback(null, list)
})
}
module.js (the file in which module_import.js has been imported.)
var filterfile = require('./module_import.js');
var dir = process.argv[2];
var ext = process.argv[3];
filterfile(dir,ext,function(err,list){
if(err){
return console.log(err);
}
list.forEach(function(file){
console.log(file);
})
});
When I run it on console by this command : node module.js \dir\path\to\files .ext
I don't get any output on the console.
Can anyone tell me what's wrong with the code?
Thanks!

Your code adds a leading period before the filter string (representing the extension you pass from the command line):
return path.extname(file) === '.' + filterStr
^^^
However, you're also passing it an extension that is preceded with a period:
node module.js \dir\path\to\files .ext
^
This will make the code try to match ..ext (two leading periods), which will fail.

Well can you check what you may be getting in process.argv[3]
moreover the issue you will be facing is with the part
list = list.filter(function (file) {
return path.extname(file) === '.' + filterStr
});
you must have checked or gave values for process.argv[3] in the question

Related

Writing to file in NodeJS calling from another JS file

I am having a weird issue writing to a file in NodeJS.
I have this code in my FileHandler.js:
module.exports.writeFile = function (arr) {
var fs = require('fs');
console.log(arr);
var file = fs.createWriteStream(__dirname+'\\test.txt',{encoding: 'utf8'});
file.on('error', function (err) {
console.log(err); });
file.on("finish", function() {
console.log("finished");
});
arr.forEach(function (item) {
file.write(item+"\n");
});
file.end();
}
If I append
exports.writeFile(["1","2","3"])
To the end of this file and then run node FileHandler.js
The file is created correctly.
However, if I call the writeFile function from another .js file as:
var R = require("r-script");
const dataHandler = require("./DataHandler");
const fileHandler = require("./FileHandler");
var out = R(__dirname + "\\apriori.R");
exports.getRules = function () {
dataHandler.getListOfPageVisitsBySession(1000781912582,1530781912582,function (result){
//ignored result variable
fileHandler.writeFile(["1","2","3"]);
})
}
and passing the exact same array to the function it doesn't write anything (but the file is created), neither fires err or finish event.
If it matters, the DataHandler method contains a request module and a GET to another API.
Any clue of the problem?
Thanks in advance

Modules with Arguments NodeJS

I have two files, home.js and module.js in the same directory.
What I'm trying to do is, I'm trying to pass the variable named directory as I call the function I exported from module.js.
It gives me this error:
binding.readdir(pathModule._makeLong(path), req);
Type error: path must be a string.
What I'm trying to figure out is, I've passed the directory variable which is process.argv[2] (contains the path) from home.js as I call the function in module.js that requires the same argument (path).
home.js
var fs = require('fs');
var path = require('path');
var module = require('./module.js');
var directory = process.argv[2];
var extensionRequired = process.argv[3];
function printList(err, data) {
if(err) return err;
list.forEach(function (file) {
if(path.extname(file) === '.' + extensionRequired) {
console.log(file);
}
});
}
module(directory, extensionRequired, printList);
module.js
var fs = require('fs');
var path = require('path');
module.exports = function (directory, extensionRequired, callBack) {
fs.readdir(directory, function(err, list) {
if(err) return err;
callBack(err, list)
});
}
I think you made a mistake, and forgot to rename the list variable:
function printList(err, data) {
if(err) return err;
// Here list => data
data.forEach(function (file) {
if(path.extname(file) === '.' + extensionRequired) {
console.log(file);
}
});
}
In your callback-method, named printList, you set the second argument as data. If you want to access the second argument's value again, you have to use data in your code or reassign it to another variable.
Your method may then look like this:
function printList(err, data) {
if (err) return err;
data.forEach(function (file) {
if(path.extname(file) === '.' + extensionRequired) {
console.log(file);
}
});
}
Additionally, I see two more problems with your code:
In module.js, you're requiring the parameter extensionRequired. If you look closely, you'll find, that it isn't even used in this method. This isn't really an error, but would in my opinion be seen as inelegant. Rather pass it trough to the printList as an additional argument (more the node-typical way IMHO) or use it as a global-scope variable as you are currently doing anyway.
In your module.exports-anonymous function from module.js, you are using if (err) return err;. I'd highly recommend you to not do such a thing. Because this is an asynchronous method, you can't really return something, as the return-statement might actually be executed after you called this method. Instead, pass your error as the first argument of the callback. If there is no error, pass null instead, so you can easily figure out if something unexpected happened. Always check that!
Your module.js could then look something like this:
var fs = require('fs');
var path = require('path');
module.exports = function (directory, callback) {
fs.readdir(directory, function(err, list) {
if (err)
// Error happened, pass it to the callback
callback(err);
else
// Everything ran smooth, send null as the error (no error)
// and the list as the second argument.
callback(null, list)
});
}
Your home.js should then be changed accordingly:
var fs = require('fs');
var path = require('path');
var module = require('./module.js');
var directory = process.argv[2];
var extensionRequired = process.argv[3];
function printList(err, data) {
if (err) {
console.error("An error occurred:", err);
// Exit with an error-code of one to
// tell failure to the calling process and
// prevent printing the probably 'undefined' data-variable
process.exit(1);
}
data.forEach(function (file) {
if(path.extname(file) === '.' + extensionRequired) {
console.log(file);
}
});
}
// extensionRequired removed, as it is not needed
module(directory, printList);

NodeJS - Given a full path of a directory, how to get a list of all subdirectories and check if a file exists here asynchronously?

For example given: '/Users/John/Desktop/FooApp',
I would like to get a list such as:
['/Users/John/Desktop/FooApp',
'/Users/John/Desktop/FooApp/Folder1',
'/Users/John/Desktop/FooApp/Folder2',
'/Users/John/Desktop/FooApp/Folder2/folderA',
'/Users/John/Desktop/FooApp/Folder3',
'/Users/John/Desktop/FooApp/Folder3/folderX',
'/Users/John/Desktop/FooApp/Folder3/folderX/folderY',
'/Users/John/Desktop/FooApp/Folder3/folderX/folderY/folderZ',
'/Users/John/Desktop/FooApp/Folder3/folderX/folderY2'
]
I require this list to search through all directories to check the existence of a file. The user inputs a folder, and I basically will perform a check similar to finders in OS. I am planning to check fs.exists(subdir + '/mylib.dll') on all the subdirectories. Is there any neat way to do that?
I have converted an answer to a similar question in here, where search was performed for files instead of directories. I also used async to check if file exists. I also found out that fs.exists was about to be deprecated and decided to go on with fs.open.
Anyway, Here is the snippet:
var fs = require('fs');
var getDirs = function(dir, cb){
var dirs = [dir];
fs.readdir(dir, function(err, list){
if(err) return cb(err);
var pending = list.length;
if(!pending) return cb(null, dirs);
list.forEach(function(subpath){
var subdir = dir + '/' + subpath;
fs.stat(subdir, function(err, stat){
if(err) return cb(err);
if(stat && stat.isDirectory()){
dirs.push(subdir);
getDirs(subdir, function(err, res){
dirs = dirs.concat(res);
if(!--pending) cb(null, dirs);
});
} else {
if(!--pending) cb(null, dirs);
}
});
});
});
};
One can then use it as:
var async = require('async');
getDirs('/Users/John/Desktop/FooApp', function(err, list){
if(err) return 'Error retrieving sub-directories';
async.detect(list, function(dir, cb){
fs.open(dir + '/mylib.dll', 'r', function(err, file){
if(err) cb(false);
else cb(true);
});
},
function(dir) {
if(!dir) return 'File Not Found';
/* Do something with the found file ... */
}
);
});

Node.JS module.exports for passing parameter between two functions?

I am new to Node.js so this is probably a fundamental question and I am missing something obvious. In the code below, I am trying to set the sql_file name from foo but I keep getting an error on the file not existing because the variable is not working. If I hard code the file name in sql_util.js it works fine.
So how do I pass a parameter or any object from one js file into the function of another?
foo.js
var misc = require('./sql_get');
console.log(misc.sql_file("on.sql"));
sql_util.js
fs = require('fs');
file = 'on.sql'
function sql_file(cb) {
var fileName = "./SQLs/" + sql_file;
fs.readFile(fileName, function(err, buffer) {
if (err) return cb(err);
return cb(null, buffer.toString());
});
}
sql_file(function(err, sqlstatement) {
if (err) throw err;
console.log('sql statement is: ' + sqlstatement);
});
};
module.exports.x = x;
module.exports.sql_fil = sql_file;
Let's go through this line by line because I see a lot of errors, both syntax and semantic.
foo.js
var misc = require('./sql_get');
console.log(misc.sql_file("on.sql"));
You defined in the function below sql_file to be asynchronous, so it does not return a value, but takes a callback that it passes the result to.
sql_util.js
fs = require('fs');
file = 'on.sql'
You have an unused module-global variable file. Remove this. It's going to cause confusion.
function sql_file(cb) {
var fileName = "./SQLs/" + sql_file;
sql_file is a function. I can tell because this code lives in a function called sql_file. Therefore, fileName will be "./SQLs/" + the .toString() result of the function, which is the source of the function. I think perhaps you want a parameter?
fs.readFile(fileName, function(err, buffer) {
if (err) return cb(err);
return cb(null, buffer.toString());
});
}
This seems ok.
sql_file(function(err, sqlstatement) {
if (err) throw err;
console.log('sql statement is: ' + sqlstatement);
});
};
I am not sure what you are trying to do here. Why are you calling the function?
module.exports.x = x;
module.exports.sql_fil = sql_file;
Both of these lines have a problem. There is no symbol defined named x. I am surprised this code runs without throwing an error on that line. Second, you are exporting sql_file as sql_fil, missing the letter e.
The Solution
Since what you asked about is parameter passing and you only have a single function, let's simplify this. You never want to use global variables. If a function needs a particular variable, just pass it as an argument.
foo.js
var misc = require('./sql_get');
misc.sql_file('on.sql', function (err, contents) {
console.log(contents);
});
sql_get.js (notice the file is renamed)
var fs = require('fs');
function sql_file(sqlFilename, cb) {
var fileName = "./SQLs/" + sqlFilename;
fs.readFile(fileName, function(err, buffer) {
if (err) return cb(err);
return cb(null, buffer.toString());
});
}
module.exports.sql_file = sql_file;
A few problems:
You're requiring sql_get but naming the other file sql_util
var misc = require('./sql_util');
You're exporting module.exports.sql_fil = sql_file; (see the missing e). You probably mean;
module.exports.sql_file = sql_file;
While calling sql_file, you are passing a string but expecting a cb in the function itself -
misc.sql_file("on.sql", function(err, fileContent) {
if(err) return console.log(err);
console.log('File content: ', fileContent);
});
function sql_file(sqlFileName, cb) {
var fileName = "./SQLs/" + sqlFileName;
fs.readFile(fileName, function(err, buffer) {
if (err) return cb(err);
return cb(null, buffer.toString());
});
}
And I don't know what you are doing with calling sql_file function in that file itself. Remove that.

Walking a directory with Node.js [duplicate]

This question already has answers here:
What is the purpose of the var keyword and when should I use it (or omit it)?
(19 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
Closed last year.
I've got a problem with this code in node.js. I want to recursively walk through a directory tree and apply the callback action to every file in the tree. This is my code at the moment:
var fs = require("fs");
// General function
var dive = function (dir, action) {
// Assert that it's a function
if (typeof action !== "function")
action = function (error, file) { };
// Read the directory
fs.readdir(dir, function (err, list) {
// Return the error if something went wrong
if (err)
return action(err);
// For every file in the list
list.forEach(function (file) {
// Full path of that file
path = dir + "/" + file;
// Get the file's stats
fs.stat(path, function (err, stat) {
console.log(stat);
// If the file is a directory
if (stat && stat.isDirectory())
// Dive into the directory
dive(path, action);
else
// Call the action
action(null, path);
});
});
});
};
The problem is that in the for each loop stat is called for every file via the variable path. When the callback is called, path already has another value and so it dives into the wrong directories or calls the action for the wrong files.
Probably this problem could easily get solved by using fs.statSync, but this is not the solution I would prefer, since it is blocking the process.
var path = dir + "/" + file;
You forgot to make path a local variable. Now it won't be changed behind your back in the loop.
Use node-dir for this. Because you need a separate action for directories and files, I'll give you 2 simple iterators using node-dir.
Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback.
var dir = require('node-dir');
dir.files(__dirname, function(err, files) {
if (err) throw err;
console.log(files);
//we have an array of files now, so now we'll iterate that array
files.forEach(function(filepath) {
actionOnFile(null, filepath);
})
});
Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of directory paths to a callback.
var dir = require('node-dir');
dir.subdirs(__dirname, function(err, subdirs) {
if (err) throw err;
console.log(subdirs);
//we have an array of subdirs now, so now we'll iterate that array
subdirs.forEach(function(filepath) {
actionOnDir(null, filepath);
})
});
Another suitable library is filehound. It supports file filtering (if required), callbacks and promises.
For example:
const Filehound = require('filehound');
function action(file) {
console.log(`process ${file}`)
}
Filehound.create()
.find((err, files) => {
if (err) {
return console.error(`error: ${err}`);
}
files.forEach(action);
});
The library is well documented and provides numerous examples of common use cases.
https://github.com/nspragg/filehound
Disclaimer: I'm the author.
Not sure if I should really post this as an answer, but for your convenience and other users, here is a rewritten version of OP's which might prove useful. It provides:
Better error management support
A global completion callback which is called when the exploration is complete
The code:
/**
* dir: path to the directory to explore
* action(file, stat): called on each file or until an error occurs. file: path to the file. stat: stat of the file (retrived by fs.stat)
* done(err): called one time when the process is complete. err is undifined is everything was ok. the error that stopped the process otherwise
*/
var walk = function(dir, action, done) {
// this flag will indicate if an error occured (in this case we don't want to go on walking the tree)
var dead = false;
// this flag will store the number of pending async operations
var pending = 0;
var fail = function(err) {
if(!dead) {
dead = true;
done(err);
}
};
var checkSuccess = function() {
if(!dead && pending == 0) {
done();
}
};
var performAction = function(file, stat) {
if(!dead) {
try {
action(file, stat);
}
catch(error) {
fail(error);
}
}
};
// this function will recursively explore one directory in the context defined by the variables above
var dive = function(dir) {
pending++; // async operation starting after this line
fs.readdir(dir, function(err, list) {
if(!dead) { // if we are already dead, we don't do anything
if (err) {
fail(err); // if an error occured, let's fail
}
else { // iterate over the files
list.forEach(function(file) {
if(!dead) { // if we are already dead, we don't do anything
var path = dir + "/" + file;
pending++; // async operation starting after this line
fs.stat(path, function(err, stat) {
if(!dead) { // if we are already dead, we don't do anything
if (err) {
fail(err); // if an error occured, let's fail
}
else {
if (stat && stat.isDirectory()) {
dive(path); // it's a directory, let's explore recursively
}
else {
performAction(path, stat); // it's not a directory, just perform the action
}
pending--; checkSuccess(); // async operation complete
}
}
});
}
});
pending--; checkSuccess(); // async operation complete
}
}
});
};
// start exploration
dive(dir);
};
Don't reinvent the wheel - use and contribute to open source instead. Try one of the following:
https://github.com/pvorb/node-dive
https://github.com/coolaj86/node-walk
There is an NPM module for this:
npm dree
Example:
const dree = require('dree');
const options = {
depth: 5, // To stop after 5 directory levels
exclude: /dir_to_exclude/, // To exclude some pahts with a regexp
extensions: [ 'txt', 'jpg' ] // To include only some extensions
};
const fileCallback = function (file) {
action(file.path);
};
let tree;
// Doing it synchronously
tree = dree.scan('./dir', options, fileCallback);
// Doing it asynchronously (returns promise)
tree = await dree.scanAsync('./dir', options, fileCallback);
// Here tree contains an object representing the whole directory tree (filtered with options)
function loop( ) {
var item = list.shift( );
if ( item ) {
// content of the loop
functionWithCallback( loop );
} else {
// after the loop has ended
whatever( );
}
}

Categories

Resources