Node js fs.exists only searching file in current directory - node.js

I have setup process.env.path variables and fs.exists(fileName). Node is not able to find the file if it is not in its currently directory.
Is there someway i can configure node to search for file in all directory mentioned in 'process.env.path'.

This isn't supported out of the box. You will have to find a suitable npm package that already does this for you or write your own code. Something along the lines of the code that is in node-whereis:
var fs = require('fs');
function whereIsMyFile(filename){
var pathSep = process.platform === 'win32' ? ';' : ':';
var directories = process.env.PATH.split(pathSep);
for (var i = 0; i < directories.length; i++) {
var path = directories[i] + '/' + filename;
if (fs.existsSync(path)) {
return path;
}
}
return null;
}

Related

Renaming multiple files asyncroniosly causing error in Node.js

I am trying to rename a bunch of pre-generated testing files (1000+) asynchronously in Node.js.
The code looks like the following:
const fs = require('fs')
const { each } = require('async')
each(files, file => {
let newfile = 'new' + file
fs.rename(file, newfile, err => {
err ? console.log(err) : console.log('renamed')
}
})
This leads to following error:
Uncaught Error: ENOENT: no such file or directory, lstat '8d3320e35d22772f'
at fs.lstatSync (fs.js:902:18)
at Object.fs.lstatSync
It's not async module issue, since replacing each with native forEach leads to the same error. Also, there are no issues when using synchronous version of rename fs.renameSync.
I think it's trying to move some file twice or so but can't figure where exactly mistake is. Made this assumption, because all files have been already renamed successfully and very likely error generated afterward. Can someone advice what causing such behavior?
My bad. Just in case someone curious, this error came from following underlying function:
function rmDir(dir) {
var list = fs.readdirSync(dir);
for(var i = 0; i < list.length; i++) {
var dirOrFile = path.join(dir, list[i]);
var stat = fs.lstatSync(dirOrFile);
if(dirOrFile == "." || dirOrFile == "..") {
// pass these files
} else if (stat.isDirectory()) {
// rmdir recursively
rmDir(dirOrFile);
}
// else { fs.unlinkSync(dirOrFile) } // rm fiilename
}
fs.rmdirSync(dir);
}

How to read from a specified file which is in a folder below without knowing the absolute path

So I have my project directory:
Here I read ArticleFile:
function _getDataFromFile() {
var jsonArray = csvjson.toObject(fs.readFileSync('ArticleFile.csv', { encoding: 'utf8' }));
var result = [];
for (var idx = 0; idx < jsonArray.length; idx++) {
var currArt = jsonArray[idx];
// if (!checkIfElementIsArticle(currArt)) throw "loaded object IS NOT an article!";
result.push(new Article(currArt.imageLocation, currArt.title, currArt.description, parseInt(currArt.quantity),parseInt(currArt.price)));
}
return result;
}
The problem is if "ArticleFile.csv" is in lets say contentsKopie I have to know the absolute path such as : C:\Users\noone_000\Desktop\BSD\Hausübungen\WebServer\WebServer\contentsKopie\ArticleFile.csv . How can I set the path like: fs.readFileSync('/ContentsCopie/ArticleFile.csv', { encoding: 'utf8' })
PS: csvjson is a module (require("csvjson"))
When you start the path with / it is interpreted as an absolute path. If you want to open a file in sub directory, you can use ./ContentsCopie/ArticleFile.csv
The . in front of the slash means that the path is relative to the current directory.
Conversely, if you needed to go up a level you can prefix your path with ..
Isn't ./contentsKopie/ArticleFile.csv enough?
When using /contentsKopie/ArticleFile.csv it's actually looking in C:/contentsKopie/ArticleFile.csv. So you have to prepend your path with a . to tell it to start at the working directory (WebServer here).
Otherwise, you can have the absolute path of the current file with __dirname then you could compose your path using the path module from node.
var path = require('path');
var article = path.join(__dirname, './contentsKopie/ArticleFile.csv');
This way, you'll get the absolute path of your file.

Get all files with specified extension node.js

I am using node.js. I want to loop through all files with extension .coffee,
but I have nowhere found an example.
Following function will return all the files in the specified directory with the regex provided.
Function
var path = require('path'), fs=require('fs');
function fromDir(startPath,filter,callback){
//console.log('Starting from dir '+startPath+'/');
if (!fs.existsSync(startPath)){
console.log("no dir ",startPath);
return;
}
var files=fs.readdirSync(startPath);
for(var i=0;i<files.length;i++){
var filename=path.join(startPath,files[i]);
var stat = fs.lstatSync(filename);
if (stat.isDirectory()){
fromDir(filename,filter,callback); //recurse
}
else if (filter.test(filename)) callback(filename);
};
};
Usage
fromDir('../LiteScript',/\.coffee$/,function(filename){
console.log('-- found: ',filename);
});

How to create full path with node's fs.mkdirSync?

I'm trying to create a full path if it doesn't exist.
The code looks like this:
var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest);
This code works great as long as there is only one subdirectory (a newDest like 'dir1') however when there is a directory path like ('dir1/dir2') it fails with
Error: ENOENT, no such file or directory
I'd like to be able to create the full path with as few lines of code as necessary.
I read there is a recursive option on fs and tried it like this
var fs = require('fs');
if (!fs.existsSync(newDest)) fs.mkdirSync(newDest,'0777', true);
I feel like it should be that simple to recursively create a directory that doesn't exist. Am I missing something or do I need to parse the path and check each directory and create it if it doesn't already exist?
I'm pretty new to Node. Maybe I'm using an old version of FS?
Update
NodeJS version 10.12.0 has added a native support for both mkdir and mkdirSync to create a directory recursively with recursive: true option as the following:
fs.mkdirSync(targetDir, { recursive: true });
And if you prefer fs Promises API, you can write
fs.promises.mkdir(targetDir, { recursive: true });
Original Answer
Create directories recursively if they do not exist! (Zero dependencies)
const fs = require('fs');
const path = require('path');
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
}
Usage
// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');
// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});
// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');
Demo
Try It!
Explanations
[UPDATE] This solution handles platform-specific errors like EISDIR for Mac and EPERM and EACCES for Windows. Thanks to all the reporting comments by #PediT., #JohnQ, #deed02392, #robyoder and #Almenon.
This solution handles both relative and absolute paths. Thanks to #john comment.
In the case of relative paths, target directories will be created (resolved) in the current working directory. To Resolve them relative to the current script dir, pass {isRelativeToScript: true}.
Using path.sep and path.resolve(), not just / concatenation, to avoid cross-platform issues.
Using fs.mkdirSync and handling the error with try/catch if thrown to handle race conditions: another process may add the file between the calls to fs.existsSync() and fs.mkdirSync() and causes an exception.
The other way to achieve that could be checking if a file exists then creating it, I.e, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. But this is an anti-pattern that leaves the code vulnerable to race conditions. Thanks to #GershomMaes comment about the directory existence check.
Requires Node v6 and newer to support destructuring. (If you have problems implementing this solution with old Node versions, just leave me a comment)
A more robust answer is to use use mkdirp.
var mkdirp = require('mkdirp');
mkdirp('/path/to/dir', function (err) {
if (err) console.error(err)
else console.log('dir created')
});
Then proceed to write the file into the full path with:
fs.writeFile ('/path/to/dir/file.dat'....
One option is to use shelljs module
npm install shelljs
var shell = require('shelljs');
shell.mkdir('-p', fullPath);
From that page:
Available options:
p: full path (will create intermediate dirs if necessary)
As others have noted, there's other more focused modules. But, outside of mkdirp, it has tons of other useful shell operations (like which, grep etc...) and it works on windows and *nix
Edit: comments suggest this doesn't work on systems that don't have mkdir cli instances. That is not the case. That's the point shelljs - create a portable cross platform set of shell like functions. It works on even windows.
fs-extra adds file system methods that aren't included in the native fs module. It is a drop in replacement for fs.
Install fs-extra
$ npm install --save fs-extra
const fs = require("fs-extra");
// Make sure the output directory is there.
fs.ensureDirSync(newDest);
There are sync and async options.
https://github.com/jprichardson/node-fs-extra/blob/master/docs/ensureDir.md
Using reduce we can verify if each path exists and create it if necessary, also this way I think it is easier to follow. Edited, thanks #Arvin, we should use path.sep to get the proper platform-specific path segment separator.
const path = require('path');
// Path separators could change depending on the platform
const pathToCreate = 'path/to/dir';
pathToCreate
.split(path.sep)
.reduce((prevPath, folder) => {
const currentPath = path.join(prevPath, folder, path.sep);
if (!fs.existsSync(currentPath)){
fs.mkdirSync(currentPath);
}
return currentPath;
}, '');
This feature has been added to node.js in version 10.12.0, so it's as easy as passing an option {recursive: true} as second argument to the fs.mkdir() call.
See the example in the official docs.
No need for external modules or your own implementation.
i know this is an old question, but nodejs v10.12.0 now supports this natively with the recursive option set to true. fs.mkdir
// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
Now with NodeJS >= 10.12.0, you can use fs.mkdirSync(path, { recursive: true }) fs.mkdirSync
Example for Windows (no extra dependencies and error handling)
const path = require('path');
const fs = require('fs');
let dir = "C:\\temp\\dir1\\dir2\\dir3";
function createDirRecursively(dir) {
if (!fs.existsSync(dir)) {
createDirRecursively(path.join(dir, ".."));
fs.mkdirSync(dir);
}
}
createDirRecursively(dir); //creates dir1\dir2\dir3 in C:\temp
You can simply check folder exist or not in path recursively and make the folder as you check if they are not present. (NO EXTERNAL LIBRARY)
function checkAndCreateDestinationPath (fileDestination) {
const dirPath = fileDestination.split('/');
dirPath.forEach((element, index) => {
if(!fs.existsSync(dirPath.slice(0, index + 1).join('/'))){
fs.mkdirSync(dirPath.slice(0, index + 1).join('/'));
}
});
}
You can use the next function
const recursiveUpload = (path: string) => {
const paths = path.split("/")
const fullPath = paths.reduce((accumulator, current) => {
fs.mkdirSync(accumulator)
return `${accumulator}/${current}`
})
fs.mkdirSync(fullPath)
return fullPath
}
So what it does:
Create paths variable, where it stores every path by itself as an element of the array.
Adds "/" at the end of each element in the array.
Makes for the cycle:
Creates a directory from the concatenation of array elements which indexes are from 0 to current iteration. Basically, it is recursive.
Hope that helps!
By the way, in Node v10.12.0 you can use recursive path creation by giving it as the additional argument.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
https://nodejs.org/api/fs.html#fs_fs_mkdirsync_path_options
Too many answers, but here's a solution without recursion that works by splitting the path and then left-to-right building it back up again
function mkdirRecursiveSync(path) {
let paths = path.split(path.delimiter);
let fullPath = '';
paths.forEach((path) => {
if (fullPath === '') {
fullPath = path;
} else {
fullPath = fullPath + '/' + path;
}
if (!fs.existsSync(fullPath)) {
fs.mkdirSync(fullPath);
}
});
};
For those concerned about windows vs Linux compatibility, simply replace the forward slash with double backslash '\' in both occurrence above but TBH we are talking about node fs not windows command line and the former is pretty forgiving and the above code will simply work on Windows and is more a complete solution cross platform.
const fs = require('fs');
try {
fs.mkdirSync(path, { recursive: true });
} catch (error) {
// this make script keep running, even when folder already exist
console.log(error);
}
An asynchronous way to create directories recursively:
import fs from 'fs'
const mkdirRecursive = function(path, callback) {
let controlledPaths = []
let paths = path.split(
'/' // Put each path in an array
).filter(
p => p != '.' // Skip root path indicator (.)
).reduce((memo, item) => {
// Previous item prepended to each item so we preserve realpaths
const prevItem = memo.length > 0 ? memo.join('/').replace(/\.\//g, '')+'/' : ''
controlledPaths.push('./'+prevItem+item)
return [...memo, './'+prevItem+item]
}, []).map(dir => {
fs.mkdir(dir, err => {
if (err && err.code != 'EEXIST') throw err
// Delete created directory (or skipped) from controlledPath
controlledPaths.splice(controlledPaths.indexOf(dir), 1)
if (controlledPaths.length === 0) {
return callback()
}
})
})
}
// Usage
mkdirRecursive('./photos/recent', () => {
console.log('Directories created succesfully!')
})
Here's my imperative version of mkdirp for nodejs.
function mkdirSyncP(location) {
let normalizedPath = path.normalize(location);
let parsedPathObj = path.parse(normalizedPath);
let curDir = parsedPathObj.root;
let folders = parsedPathObj.dir.split(path.sep);
folders.push(parsedPathObj.base);
for(let part of folders) {
curDir = path.join(curDir, part);
if (!fs.existsSync(curDir)) {
fs.mkdirSync(curDir);
}
}
}
How about this approach :
if (!fs.existsSync(pathToFile)) {
var dirName = "";
var filePathSplit = pathToFile.split('/');
for (var index = 0; index < filePathSplit.length; index++) {
dirName += filePathSplit[index]+'/';
if (!fs.existsSync(dirName))
fs.mkdirSync(dirName);
}
}
This works for relative path.
Based on mouneer's zero-dependencies answer, here's a slightly more beginner friendly Typescript variant, as a module:
import * as fs from 'fs';
import * as path from 'path';
/**
* Recursively creates directories until `targetDir` is valid.
* #param targetDir target directory path to be created recursively.
* #param isRelative is the provided `targetDir` a relative path?
*/
export function mkdirRecursiveSync(targetDir: string, isRelative = false) {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelative ? __dirname : '.';
targetDir.split(sep).reduce((prevDirPath, dirToCreate) => {
const curDirPathToCreate = path.resolve(baseDir, prevDirPath, dirToCreate);
try {
fs.mkdirSync(curDirPathToCreate);
} catch (err) {
if (err.code !== 'EEXIST') {
throw err;
}
// caught EEXIST error if curDirPathToCreate already existed (not a problem for us).
}
return curDirPathToCreate; // becomes prevDirPath on next call to reduce
}, initDir);
}
As clean as this :)
function makedir(fullpath) {
let destination_split = fullpath.replace('/', '\\').split('\\')
let path_builder = destination_split[0]
$.each(destination_split, function (i, path_segment) {
if (i < 1) return true
path_builder += '\\' + path_segment
if (!fs.existsSync(path_builder)) {
fs.mkdirSync(path_builder)
}
})
}
I had issues with the recursive option of fs.mkdir so I made a function that does the following:
Creates a list of all directories, starting with the final target dir and working up to the root parent.
Creates a new list of needed directories for the mkdir function to work
Makes each directory needed, including the final
function createDirectoryIfNotExistsRecursive(dirname) {
return new Promise((resolve, reject) => {
const fs = require('fs');
var slash = '/';
// backward slashes for windows
if(require('os').platform() === 'win32') {
slash = '\\';
}
// initialize directories with final directory
var directories_backwards = [dirname];
var minimize_dir = dirname;
while (minimize_dir = minimize_dir.substring(0, minimize_dir.lastIndexOf(slash))) {
directories_backwards.push(minimize_dir);
}
var directories_needed = [];
//stop on first directory found
for(const d in directories_backwards) {
if(!(fs.existsSync(directories_backwards[d]))) {
directories_needed.push(directories_backwards[d]);
} else {
break;
}
}
//no directories missing
if(!directories_needed.length) {
return resolve();
}
// make all directories in ascending order
var directories_forwards = directories_needed.reverse();
for(const d in directories_forwards) {
fs.mkdirSync(directories_forwards[d]);
}
return resolve();
});
}
I solved the problem this way - similar to other recursive answers but to me this is much easier to understand and read.
const path = require('path');
const fs = require('fs');
function mkdirRecurse(inputPath) {
if (fs.existsSync(inputPath)) {
return;
}
const basePath = path.dirname(inputPath);
if (fs.existsSync(basePath)) {
fs.mkdirSync(inputPath);
}
mkdirRecurse(basePath);
}
Could not find an example to create dir's with the required permissions.
Create Directories async recursively with the permissions you want.
Heres a plain nodejs solution
node v18.12.1
Ubuntu 18
//-----------------------------
const fs = require('fs');
const fsPromises = fs.promises;
const checkDirAccess = async (userDir) => {
try {
await fsPromises.access(userDir, fs.constants.R_OK | fs.constants.W_OK);
console.log(` ${userDir} Dir existss`);
return userDir;
} catch (err) {
if(err.errno = -2)
return await crDir(userDir);
else
throw err;
}
}
const crDir = async (userDir) => {
try {
let newDir = await fsPromises.mkdir(userDir, { recursive: true, mode: 0o700});
// When userDir is created; newDir = undefined;
console.log(` Created new Dir ${newDir}`);
return newDir;
} catch (err) {
throw err;
}
}
const directoryPath = ['uploads/xvc/xvc/xvc/specs', 'uploads/testDir11', 'uploads/xsXa/', 'uploads//xsb//', 'uploads//xsV/'];
const findDir = async() => {
try {
for (const iterator of directoryPath) {
let dirOK = await checkDirAccess(iterator);
if(dirOK)
console.log(`found ${dirOK}`)
}
} catch (error) {
console.error('Error : ', error);
}
}
Exec can be messy on windows. There is a more "nodie" solution. Fundamentally, you have a recursive call to see if a directory exists and dive into the child (if it does exist) or create it. Here is a function that will create the children and call a function when finished:
fs = require('fs');
makedirs = function(path, func) {
var pth = path.replace(/['\\]+/g, '/');
var els = pth.split('/');
var all = "";
(function insertOne() {
var el = els.splice(0, 1)[0];
if (!fs.existsSync(all + el)) {
fs.mkdirSync(all + el);
}
all += el + "/";
if (els.length == 0) {
func();
} else {
insertOne();
}
})();
}
This version works better on Windows than the top answer because it understands both / and path.sep so that forward slashes work on Windows as they should. Supports absolute and relative paths (relative to the process.cwd).
/**
* Creates a folder and if necessary, parent folders also. Returns true
* if any folders were created. Understands both '/' and path.sep as
* path separators. Doesn't try to create folders that already exist,
* which could cause a permissions error. Gracefully handles the race
* condition if two processes are creating a folder. Throws on error.
* #param targetDir Name of folder to create
*/
export function mkdirSyncRecursive(targetDir) {
if (!fs.existsSync(targetDir)) {
for (var i = targetDir.length-2; i >= 0; i--) {
if (targetDir.charAt(i) == '/' || targetDir.charAt(i) == path.sep) {
mkdirSyncRecursive(targetDir.slice(0, i));
break;
}
}
try {
fs.mkdirSync(targetDir);
return true;
} catch (err) {
if (err.code !== 'EEXIST') throw err;
}
}
return false;
}

Retrieving files from Directory Node Js

I am using readDirSync to get the files from a Diretory. PLease find the code and error as following.
var fs = require('fs');
var files = fs.readdirSync('./application/models/');
for(var i in files) {
var definition = require('../application/models/'+files[i]).Model;
console.log('Model Loaded: ' + files[i]);
}
I am getting error for line number 2 .
ENOENT, No such file or directory './application/models/' at Object.readdirSync (fs.js:376:18)
I have application/models on the same dir. I already checked for '/application/models/' and
'application/models/' but failed. I can see the same thing running on server.
Please help
Thanks
If you are using relative path when calling readdirSync, make sure it is relative to process.cwd().
However, "require" should be relative to the current script.
For example, given the following structure
server.js (node process)
/lib/importer.js (the current script)
/lib/application/models/
you may need to write importer.js as:
var fs = require('fs');
var files = fs.readdirSync('./lib/application/models/');
for (var i in files) {
var definition = require('./application/models/' + files[i]).Model;
console.log('Model Loaded: ' + files[i]);
}
Have you tried the following?
var files = fs.readdirSync(__dirname+'/application/models/');

Resources