Move all files in directory to parent with node.js - node.js

Question
Is there a simple way to move all the files in a directory up to its parent directory then delete the directory?
Use Case
I'm doing a zip extraction and the source zip contains a root folder called archive, so when I extract I get extract_path/archive/, but I'd like to just extract the contents of archive directly to extract_path.
I thought this would be simple rename, but the following is throwing a "There is a file in the way" error message.
fs.renameSync(extractPath + "/archive", extractPath)

use the mv npm module. mv first tries a fs.rename, and if it fails, uses copy then unlink :
mv('source/dir', 'dest/a/b/c/dir', {mkdirp: true}, function(err) {
// done. it first created all the necessary directories, and then
// tried fs.rename, then falls back to using ncp to copy the dir
// to dest and then rimraf to remove the source dir
});
or spawn a child process :
var spawn = require('child_process').spawn,
mv = spawn('mv', ['/dir1/dir2/*','dir1/']);

The selected answer does not work:
var mv = require('mv');
var extractPath = 'E:\\tmp\\dir';
mv(extractPath + "\\sub", extractPath, {mkdirp: true}, console.error);
It errors with:
{ Error: EPERM: operation not permitted, rename 'E:\tmp\dir\sub' -> 'E:\tmp\dir'
at Error (native)
errno: -4048,
code: 'EPERM',
syscall: 'rename',
path: 'E:\\tmp\\dir\\sub',
dest: 'E:\\tmp\\dir' }
Use fs-extra instead of mv:
var fs = require('fs-extra');
var extractPath = 'E:\\tmp\\dir';
fs.move(extractPath + "\\sub", extractPath, console.error);
My file structure is like this before the move:
E:\tmp\dir
> sub
> doc.txt
And like this after the move:
E:\tmp\dir
> doc.txt
UPDATE:
While the above works on Windows, on Linux I get the same error even when using fs-extra. The below is a manual fix for this, by individually moving each child of the subdirectory up to the parent. If a child move fails, then it will revert any other successful moves back to the original location in the subdirectory.
var fs = require('fs-extra')
var Promise = require('promise');
var path = require('path');
var promiseAllWait = function(promises) {
// this is the same as Promise.all(), except that it will wait for all promises to fulfill before rejecting
var all_promises = [];
for(var i_promise=0; i_promise < promises.length; i_promise++) {
all_promises.push(
promises[i_promise]
.then(function(res) {
return { res: res };
}).catch(function(err) {
return { err: err };
})
);
}
return Promise.all(all_promises)
.then(function(results) {
return new Promise(function(resolve, reject) {
var is_failure = false;
var i_result;
for(i_result=0; i_result < results.length; i_result++) {
if (results[i_result].err) {
is_failure = true;
break;
} else {
results[i_result] = results[i_result].res;
}
}
if (is_failure) {
reject( results[i_result].err );
} else {
resolve(results);
}
});
});
};
var movePromiser = function(from, to, records) {
return fs.move(from, to)
.then(function() {
records.push( {from: from, to: to} );
});
};
var moveDir = function(from_dir, to_dir) {
return fs.readdir(from_dir)
.then(function(children) {
return fs.ensureDir(to_dir)
.then(function() {
var move_promises = [];
var moved_records = [];
var child;
for(var i_child=0; i_child < children.length; i_child++) {
child = children[i_child];
move_promises.push(movePromiser(
path.join(from_dir, child),
path.join(to_dir, child),
moved_records
));
}
return promiseAllWait(move_promises)
.catch(function(err) {
var undo_move_promises = [];
for(var i_moved_record=0; i_moved_record < moved_records.length; i_moved_record++) {
undo_move_promises.push( fs.move(moved_records[i_moved_record].to, moved_records[i_moved_record].from) );
}
return promiseAllWait(undo_move_promises)
.then(function() {
throw err;
});
});
}).then(function() {
return fs.rmdir(from_dir);
});
});
};

Non of the answers work for me, I looked deep in mv's code and found my solution:
I move folder/subfolder to folder, so the folder already exists.
mv(oldPath, newPath, {mkdirp: false, clobber: false}, (err) => {
if (err) {
throw err;
}
});
Remember if the filename already exists in parent folder it will overwrite by file inside subfolder.

Related

How to zip a single file with Archiver

I am trying to zip a single file using the Archiver npm package located: https://www.npmjs.com/package/archiver
I have been able to use the following to zip a directory:
archive.directory(folderName, false);
But when I try to use either of these nothing seems to happen (ie: no zip is generated, file never finishes zipping):
archive.file(folderName, { name: 'file4.txt' });
archive.file(fs.createReadStream(path.resolve(file)), {name: 'File' + singleFileCheck});
Has anyone run into this issue before? Please let me know what I am doing wrong. Thank you in advance!
edit:
module.exports = async function zipper(user, pass, orgid, s4url, apiToken, newOrgName, file) {
const s4 = require('../testcli/s4');
const fs = require('fs');
const archiver = require('archiver');
const path = require('path');
var parentDirect;
if(file == "./"){
parentDirect = "..";
}else{
parentDirect = path.basename(path.dirname(file));
}
const newZipFile = parentDirect + '/s4.zip';
var folderName = file;
//Checks for existence of infinite loop
if(path.resolve(parentDirect).length > path.resolve(folderName).length){
console.log(folderName.search(parentDirect));
console.error('\x1b[36m%s\x1b[0m', 'ERROR!!!! : Please adjust where your console is pointed, this will result in an infinite loop. Exiting.');
return;
}
var P = ['\\', '|', '/', '-'];
var x = 0;
var output = fs.createWriteStream(newZipFile);
var archive = archiver('zip');
scansdisplayinterval = setInterval(function () {
twrl();
}, 250);
// listen for all archive data to be written
output.on('close', function () {
console.log('\x1b[36m%s\x1b[0m', archive.pointer() + ' total bytes');
console.log('\x1b[36m%s\x1b[0m', 'archiver has been finalized and the output file descriptor has closed.');
try {
process.stdout.write(newZipFile);
clearInterval(scansdisplayinterval);
s4(user, pass, newZipFile, orgid, s4url, apiToken, newOrgName);
} catch (e) {
console.log(e);
}
});
// good practice to catch this error explicitly
archive.on('error', function (err) {
throw err;
});
// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function(err) {
throw err;
});
// This event is fired when the data source is drained no matter what was the data source.
output.on('end', function() {
console.log('\x1b[36m%s\x1b[0m', 'Data has been drained');
});
// pipe archive data to the file
archive.pipe(output);
//Checks -f for file extension
let singleFileCheck = path.extname(file);
//If file has extension
if(singleFileCheck.length <= 4 && singleFileCheck != ''){
//Append single file
console.log('singleFile', path.resolve(file));
archive.file(path.resolve(file), { name: 'file4.txt' });
// archive.append(fs.createReadStream(path.resolve(file)), {name: 'File' + singleFileCheck});
//Else = folder
}else{
// append files from a sub-directory, putting its contents at the root of archive
archive.directory(folderName, false);
}
// archive.directory(folderName, false);
console.log('\x1b[36m%s\x1b[0m', "Zipping: " + folderName + " To: " + newZipFile);
console.log('\x1b[36m%s\x1b[0m', "Zipping To: " + path.resolve(newZipFile));
archive.finalize();
function twrl() {
process.stdout.write('\rZipping Folder ... ' + P[x++]);
x &= 3;
}
return(newZipFile);
};
The issue came from how I was defining the parentDirect var.
Solution:
let singleFileCheck = path.extname(file);
if(file == "./" || singleFileCheck.length <= 4 && singleFileCheck != ''){
parentDirect = "..";
}else{
parentDirect = path.basename(path.dirname(file));
}

Why is fs.readFile triggering "Error: EMFILE: too many open files" and how can I fix it?

I've been using this load method on a file manager class:
const fs = require('fs')
const path = require('path');
const isJson = require.main.require('../js/funcs/is-json.js');
let fileCount = 0;
module.exports = class {
constructor() {
this.cache = {};
}
// .. snip ..
load(pathName, raw = false, cache = false) {
if (!raw) pathName = "." + pathName + ".js";
return new Promise((resolve, reject) => {
if (cache && this.cache[pathName]) {
//console.log("returned memory cached file", pathName);
resolve(this.cache[pathName]);
} else {
fileCount++;
fs.readFile(pathName, (err, data) => {
console.log("files read", fileCount);
if (err) {
throw err;
} else {
//console.log("loaded file", pathName)
if (isJson(data)) {
let parsed = JSON.parse(data);
if (cache) this.cache[pathName] = parsed;
resolve(parsed);
} else {
//console.log("ignored bad JSON", data);
resolve(false);
}
}
});
}
});
}
// ... snip ...
}
And now I'm getting the error:
files read 8774
C:\Users\jonat\.. proj path ..\js\classes\storage.js:55
throw err;
^
[Error: EMFILE: too many open files, open 'C:\Users\jonat\.. proj path ..\cache\v1\markets\myfilename1.json'] {
errno: -4066,
code: 'EMFILE',
syscall: 'open',
path: 'C:\\Users\\jonat\\.. proj path ..\\cache\\v1\\markets\\myfilename1.json'
}
And as you can see in the logs and code, I added a fileCounter variable to iterate on each fs.readFile call and see if I'm opening some massively high number of files, but the count appears to be at just 5 (Edit: 8774 once I moved the iterator to before the file is actually read) when the error gets logged. Also, I thought fs.readFile would close the files when done reading, so I shouldn't have a large number of files opened at once. What's going on here and how can I better debug / fix this?
Edit: see changes to iterator count.
I know just-library solutions are usually frowned upon here, but hostly, the graceful-fs node.js module was the perfect fix here. https://github.com/isaacs/node-graceful-fs
Just installed it and replaced
const fs = require('fs')
with
const fs = require('graceful-fs')
And my code magically worked again

Gulp: Abnormal behavior of program

I'm new to Gulp and I'm having a problem with gulp,here are some points that I want to be done
I want to lookup for a file that has an .storyboard extension
(it is already DONE)
I want to perform a task whenever a certain file's content is
changed,
I want to Watch that file and when something is being changed in
that file
I want to rewrite its content by removing all other content that was
already in the file.
When I make changes in file with .storyboard extension, it just keep on displaying a message done, file has been saved
Here is my Code:
//fs to read and write files while path is for iterating directories
fs = require('fs'),
path = require('path')
//DomParser to Parse Xml
var DOMParser = new (require('xmldom')).DOMParser({ normalizeTags: { default: false } });
//Gulp for detecting changes
var gulp = require('gulp')
var mainStoryBoardFile;
function crawl(dir) {
// console.log('[+]', dir);
var files = fs.readdirSync(dir);
for (var file in files) {
var next = path.join(dir, files[file]);
//iterate through files to check whether next is a file or direcory
if (fs.lstatSync(next).isDirectory()) {
//if its a directory dive into it
crawl(next);
} else if (next.indexOf('.storyboard') >= 0) {
//if its a file just check it whether it is a .storyboard file or not
mainStoryBoardFile = next;
mainStoryBoardFile = mainStoryBoardFile.replace(/\\/g, "/");
};
}
}
//calling function
crawl(__dirname);
var newFilePath = './data.xml'
var document;
var dataFound;
//What to do
gulp.task('read', function (done) {
dataFound = fs.readFileSync(mainStoryBoardFile, "utf-8");
document = DOMParser.parseFromString(
dataFound.toString()
);
done();
});
gulp.task('write', function (done) {
fs.writeFile(mainStoryBoardFile, '', function () { console.log('done') })
fs.writeFile(mainStoryBoardFile, document, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
done();
});
gulp.task('watch', function (done) {
gulp.watch(mainStoryBoardFile, gulp.series('read', 'write'));
});
Here is a solution to solve this problem, You can watch changes on a single file and you can also perform some sort of function whenever a file is changed. in xml case, you can watch a file, when it changes you can add new properties or attributes or you can create new elements in xml file.
//Dependencies
//fs to read and write files while path is for iterating directories
var fs = require('fs'),
path = require('path'),
DOMParser = new (require('xmldom')).DOMParser({ normalizeTags: { default: false } }),
gulp = require('gulp'),
arrayOfControls = require('./object.json'),
RandExp = require('randexp');
console.log("GulpService has been Started\n");
function crawl(dir) {
var files = fs.readdirSync(dir);
for (var file in files) {
var next = path.join(dir, files[file]);
//iterate through files to check whether next is a file or direcory
if (fs.lstatSync(next).isDirectory()) {
//if its a directory dive into it
crawl(next);
} else if (next.indexOf('.storyboard') >= 0) {
//if its a file just check it whether it is a .storyboard file or not
mainStoryBoardFile = next;
mainStoryBoardFile = mainStoryBoardFile.replace(/\\/g, "/");
}
}
}
//calling function
crawl(__dirname);
var mainStoryBoardFile;
var document, dataFound;
function readWrite() {
crawl(__dirname);
dataFound = fs.readFileSync(mainStoryBoardFile, "utf-8");
document = DOMParser.parseFromString(
dataFound.toString()
);
fs.writeFileSync(mainStoryBoardFile, '', function () {
console.log('done')
});
fs.writeFileSync(mainStoryBoardFile, document, (err) => {
if (err) throw err;
console.log('The file has been saved!');
});
}
var watcher = gulp.watch(mainStoryBoardFile);
watcher.on('change', function (path, stats) {
readWrite();
console.log('File ' + path + ' was changed');
watcher.unwatch(mainStoryBoardFile);
watcher.add(mainStoryBoardFile);
});

How to create a directory if it doesn't exist using Node.js

Is the following the right way to create a directory if it doesn't exist?
It should have full permission for the script and readable by others.
var dir = __dirname + '/upload';
if (!path.existsSync(dir)) {
fs.mkdirSync(dir, 0744);
}
For individual dirs:
var fs = require('fs');
var dir = './tmp';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
Or, for nested dirs:
var fs = require('fs');
var dir = './tmp/but/then/nested';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir, { recursive: true });
}
No, for multiple reasons.
The path module does not have an exists/existsSync method. It is in the fs module. (Perhaps you just made a typo in your question?)
The documentation explicitly discourage you from using exists.
fs.exists() is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.
In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.
Since we're talking about a directory rather than a file, this advice implies you should just unconditionally call mkdir and ignore EEXIST.
In general, you should avoid the *Sync methods. They're blocking, which means absolutely nothing else in your program can happen while you go to the disk. This is a very expensive operation, and the time it takes breaks the core assumption of node's event loop.
The *Sync methods are usually fine in single-purpose quick scripts (those that do one thing and then exit), but should almost never be used when you're writing a server: your server will be unable to respond to anyone for the entire duration of the I/O requests. If multiple client requests require I/O operations, your server will very quickly grind to a halt.
The only time I'd consider using *Sync methods in a server application is in an operation that happens once (and only once), at startup. For example, require actually uses readFileSync to load modules.
Even then, you still have to be careful because lots of synchronous I/O can unnecessarily slow down your server's startup time.
Instead, you should use the asynchronous I/O methods.
So if we put together those pieces of advice, we get something like this:
function ensureExists(path, mask, cb) {
if (typeof mask == 'function') { // Allow the `mask` parameter to be optional
cb = mask;
mask = 0o744;
}
fs.mkdir(path, mask, function(err) {
if (err) {
if (err.code == 'EEXIST') cb(null); // Ignore the error if the folder already exists
else cb(err); // Something else went wrong
} else cb(null); // Successfully created folder
});
}
And we can use it like this:
ensureExists(__dirname + '/upload', 0o744, function(err) {
if (err) // Handle folder creation error
else // We're all good
});
Of course, this doesn't account for edge cases like
What happens if the folder gets deleted while your program is running? (assuming you only check that it exists once during startup)
What happens if the folder already exists, but with the wrong permissions?
The mkdir method has the ability to recursively create any directories in a path that don't exist, and ignore the ones that do.
From the Node.js v10/11 documentation:
// Creates /tmp/a/apple, regardless of whether `/tmp` and /tmp/a exist.
fs.mkdir('/tmp/a/apple', { recursive: true }, (err) => {
if (err) throw err;
});
NOTE: You'll need to import the built-in fs module first.
Now here's a little more robust example that leverages native ECMAScript Modules (with flag enabled and .mjs extension), handles non-root paths, and accounts for full pathnames:
import fs from 'fs';
import path from 'path';
function createDirectories(pathname) {
const __dirname = path.resolve();
pathname = pathname.replace(/^\.*\/|\/?[^\/]+\.[a-z]+|\/$/g, ''); // Remove leading directory markers, and remove ending /file-name.extension
fs.mkdir(path.resolve(__dirname, pathname), { recursive: true }, e => {
if (e) {
console.error(e);
} else {
console.log('Success');
}
});
}
You can use it like createDirectories('/components/widget/widget.js');.
And of course, you'd probably want to get more fancy by using promises with async/await to leverage file creation in a more readable synchronous-looking way when the directories are created; but, that's beyond the question's scope.
With the fs-extra package you can do this with a one-liner:
const fs = require('fs-extra');
const dir = '/tmp/this/path/does/not/exist';
fs.ensureDirSync(dir);
I have found an npm module that works like a charm for this.
It simply does a recursive mkdir when needed, like a "mkdir -p ".
The one line version:
// Or in TypeScript: import * as fs from 'fs';
const fs = require('fs');
!fs.existsSync(dir) && fs.mkdirSync(dir);
You can just use mkdir and catch the error if the folder exists.
This is async (so best practice) and safe.
fs.mkdir('/path', err => {
if (err && err.code != 'EEXIST') throw 'up'
.. safely do your stuff here
})
(Optionally add a second argument with the mode.)
Other thoughts:
You could use then or await by using native promisify.
const util = require('util'), fs = require('fs');
const mkdir = util.promisify(fs.mkdir);
var myFunc = () => { ..do something.. }
mkdir('/path')
.then(myFunc)
.catch(err => { if (err.code != 'EEXIST') throw err; myFunc() })
You can make your own promise method, something like (untested):
let mkdirAsync = (path, mode) => new Promise(
(resolve, reject) => mkdir (path, mode,
err => (err && err.code !== 'EEXIST') ? reject(err) : resolve()
)
)
For synchronous checking, you can use:
fs.existsSync(path) || fs.mkdirSync(path)
Or you can use a library, the two most popular being
mkdirp (just does folders)
fsextra (supersets fs, adds lots of useful stuff)
solutions
CommonJS
const fs = require('fs');
const path = require('path');
const dir = path.resolve(path.join(__dirname, 'upload');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
// OR
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
mode: 0o744, // Not supported on Windows. Default: 0o777
});
}
ESM
update your package.json file config
{
// declare using ECMAScript modules(ESM)
"type": "module",
//...
}
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// create one custom `__dirname`, because it does not exist in es-module env ⚠️
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const dir = path.resolve(path.join(__dirname, 'upload');
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
// OR
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
mode: 0o744, // Not supported on Windows. Default: 0o777
});
}
update 2022
import { existsSync } from 'node:fs';
refs
NodeJS Version: v18.2.0
https://nodejs.org/api/fs.html#fsexistssyncpath
https://nodejs.org/api/fs.html#fsmkdirsyncpath-options
https://nodejs.org/api/url.html#urlfileurltopathurl
https://github.com/nodejs/help/issues/2907#issuecomment-757446568
ESM: ECMAScript modules
https://nodejs.org/api/esm.html#introduction
One-line solution: Creates the directory if it does not exist
// import
const fs = require('fs') // In JavaScript
import * as fs from "fs" // in TypeScript
import fs from "fs" // in Typescript
// Use
!fs.existsSync(`./assets/`) && fs.mkdirSync(`./assets/`, { recursive: true })
The best solution would be to use the npm module called node-fs-extra. It has a method called mkdir which creates the directory you mentioned. If you give a long directory path, it will create the parent folders automatically. The module is a superset of npm module fs, so you can use all the functions in fs also if you add this module.
var dir = 'path/to/dir';
try {
fs.mkdirSync(dir);
} catch(e) {
if (e.code != 'EEXIST') throw e;
}
Use:
var filessystem = require('fs');
var dir = './path/subpath/';
if (!filessystem.existsSync(dir))
{
filessystem.mkdirSync(dir);
}
else
{
console.log("Directory already exist");
}
For node v10 and above
As some answers pointed out, since node 10 you can use recursive:true for mkdir
What is not pointed out yet, is that when using recursive:true, mkdir does not return an error if the directory already existed.
So you can do:
fsNative.mkdir(dirPath,{recursive:true},(err) => {
if(err) {
//note: this does NOT get triggered if the directory already existed
console.warn(err)
}
else{
//directory now exists
}
})
Using promises
Also since node 10, you can get Promise versions of all fs functions by requiring from fs/promises
So putting those two things together, you get this simple solution:
import * as fs from 'fs/promises';
await fs.mkdir(dirPath, {recursive:true}).catch((err) => {
//decide what you want to do if this failed
console.error(err);
});
//directory now exists
fs.exist() is deprecated. So I have used fs.stat() to check the directory status. If the directory does not exist, fs.stat() throws an error with a message like 'no such file or directory'. Then I have created a directory.
const fs = require('fs').promises;
const dir = './dir';
fs.stat(dir).catch(async (err) => {
if (err.message.includes('no such file or directory')) {
await fs.mkdir(dir);
}
});
With Node.js 10 + ES6:
import path from 'path';
import fs from 'fs';
(async () => {
const dir = path.join(__dirname, 'upload');
try {
await fs.promises.mkdir(dir);
} catch (error) {
if (error.code === 'EEXIST') {
// Something already exists, but is it a file or directory?
const lstat = await fs.promises.lstat(dir);
if (!lstat.isDirectory()) {
throw error;
}
} else {
throw error;
}
}
})();
I'd like to add a TypeScript Promise refactor of josh3736's answer.
It does the same thing and has the same edge cases. It just happens to use Promises, TypeScript typedefs, and works with "use strict".
// https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation
const allRWEPermissions = parseInt("0777", 8);
function ensureFilePathExists(path: string, mask: number = allRWEPermissions): Promise<void> {
return new Promise<void>(
function(resolve: (value?: void | PromiseLike<void>) => void,
reject: (reason?: any) => void): void{
mkdir(path, mask, function(err: NodeJS.ErrnoException): void {
if (err) {
if (err.code === "EEXIST") {
resolve(null); // Ignore the error if the folder already exists
} else {
reject(err); // Something else went wrong
}
} else {
resolve(null); // Successfully created folder
}
});
});
}
I had to create sub-directories if they didn't exist. I used this:
const path = require('path');
const fs = require('fs');
function ensureDirectoryExists(p) {
//console.log(ensureDirectoryExists.name, {p});
const d = path.dirname(p);
if (d && d !== p) {
ensureDirectoryExists(d);
}
if (!fs.existsSync(d)) {
fs.mkdirSync(d);
}
}
You can use the Node.js File System command fs.stat to check if a directory exists and fs.mkdir to create a directory with callback, or fs.mkdirSync to create a directory without callback, like this example:
// First require fs
const fs = require('fs');
// Create directory if not exist (function)
const createDir = (path) => {
// Check if dir exist
fs.stat(path, (err, stats) => {
if (stats.isDirectory()) {
// Do nothing
} else {
// If the given path is not a directory, create a directory
fs.mkdirSync(path);
}
});
};
From the documentation this is how you do it asynchronously (and recursively):
const fs = require('fs');
const fsPromises = fs.promises;
fsPromises.access(dir, fs.constants.F_OK)
.catch(async() => {
await fs.mkdir(dir, { recursive: true }, function(err) {
if (err) {
console.log(err)
}
})
});
Here is a little function to recursivlely create directories:
const createDir = (dir) => {
// This will create a dir given a path such as './folder/subfolder'
const splitPath = dir.split('/');
splitPath.reduce((path, subPath) => {
let currentPath;
if(subPath != '.'){
currentPath = path + '/' + subPath;
if (!fs.existsSync(currentPath)){
fs.mkdirSync(currentPath);
}
}
else{
currentPath = subPath;
}
return currentPath
}, '')
}
my solutions
CommonJS
var fs = require("fs");
var dir = __dirname + '/upload';
// if (!fs.existsSync(dir)) {
// fs.mkdirSync(dir);
// }
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
mode: 0o744,
});
// mode's default value is 0o744
}
ESM
update package.json config
{
//...
"type": "module",
//...
}
import fs from "fs";
import path from "path";
// create one custom `__dirname`, because it not exist in es-module env ⚠️
const __dirname = path.resolve();
const dir = __dirname + '/upload';
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
// OR
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, {
mode: 0o744,
});
// mode's default value is 0o744
}
refs
https://nodejs.org/api/fs.html#fsexistssyncpath
https://github.com/nodejs/help/issues/2907#issuecomment-671782092
Using async / await:
const mkdirP = async (directory) => {
try {
return await fs.mkdirAsync(directory);
} catch (error) {
if (error.code != 'EEXIST') {
throw e;
}
}
};
You will need to promisify fs:
import nodeFs from 'fs';
import bluebird from 'bluebird';
const fs = bluebird.promisifyAll(nodeFs);
A function to do this asynchronously (adjusted from a similar answer on SO that used sync functions, that I can't find now)
// ensure-directory.js
import { mkdir, access } from 'fs'
/**
* directoryPath is a path to a directory (no trailing file!)
*/
export default async directoryPath => {
directoryPath = directoryPath.replace(/\\/g, '/')
// -- preparation to allow absolute paths as well
let root = ''
if (directoryPath[0] === '/') {
root = '/'
directoryPath = directoryPath.slice(1)
} else if (directoryPath[1] === ':') {
root = directoryPath.slice(0, 3) // c:\
directoryPath = directoryPath.slice(3)
}
// -- create folders all the way down
const folders = directoryPath.split('/')
let folderPath = `${root}`
for (const folder of folders) {
folderPath = `${folderPath}${folder}/`
const folderExists = await new Promise(resolve =>
access(folderPath, error => {
if (error) {
resolve(false)
}
resolve(true)
})
)
if (!folderExists) {
await new Promise((resolve, reject) =>
mkdir(folderPath, error => {
if (error) {
reject('Error creating folderPath')
}
resolve(folderPath)
})
)
}
}
}

Express.js throws Error: ENOENT on linux server

So, I have been working on an upload script (code is below) that I have working on my windows machine, but on my Linux server it seems to fail with
Error: ENOENT, open 'uploads/da5ab67b48ea2deecd25127186017083'
I understand that the error is saying there is no path/file, but I do check to for file existence before I attempt the file rename.
exports.product_files_upload = function (req, res) {
if (req.files) {
var tmpArray = [];
for(var file in req.files){
console.log(file)
if (file){
var splitName = file.split('-');
if (splitName.length > 1) {
var username = splitName[0];
var productId = splitName[1];
var index = splitName[2];
} else {
return;
}
} else {
return;
}
//console.log(username)
//console.log(productId)
var tmp_path = req.files[file].path;
console.log(fs.existsSync(tmp_path))
createUserDir();
createProductDirs(username, productId);
//console.log(__dirname)
var target_path = './public/user_files/'+ username + '/products/'+productId+'/files/' + req.files[file].name,
save_path = 'user_files/'+ username + '/products/'+productId+'/files/' + req.files[file].name;
if (fs.existsSync(target_path)) {
tmpArray.push({exists:true, name:req.files[file].name});
} else {
tmpArray.push({
size: req.files[file].size,
type: req.files[file].type,
name: req.files[file].name,
path: save_path,
exists:false
});
if (fs.existsSync(tmp_path)) {
fs.rename(tmp_path, target_path, function(err) {
if (err) throw err;
// delete the temporary file, so that the explicitly set temporary upload dir does not get filled with unwanted files
fs.unlink(tmp_path, function() {
if (err) throw err;
// res.send(save_path);
});
});
} else {
tmpArray.push({
size: req.files[file].size,
type: req.files[file].type,
name: req.files[file].name,
path: save_path,
exists:false
});
}
}
}
res.json(tmpArray);
}
};
UPDATE: I am using forever for running my express app, and when I stopped my app forever process and switched to just "node app.js" the problem was fixed. This is not an acceptable fix. I am thinking there might be a problem with forever.
Okay, I figured it out. I was using forever with an absolute path to launch my app on my linux box like
forever start /path/to/app.js
But when I cd into the app directory and then launch the app it works.
forever start app.js

Resources