You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After noticing in the node docs that fs.exists and fs.existsSync were going to be deprecated, I took at look at the iojs docs to see that it had in fact been.
This is really annoying and seems like it's based out of the assumption that every developer ever is only checking the existence of a file prior to reading/writing in some async context. While I understand the sentiment behind wanting to avoid 'unnecessary abstractions' or race conditions, this is unnecessary.
Whereas I was previously able to handle the checking of a file's existence with a single boolean variable, I'm now given no other option but to either try/catch or make my code async and listen for error events.
This feels like prescriptivism, as I can't think of a single reason why a stern warning of the potential implications and/or examples of caveats to its use wouldn't have sufficed.
Can anyone help me understand why this was necessary (beyond pushing the all-async-all-the-time paradigm (that doesn't always necessarily apply (particularly in the case of synchronous CLI tooling)))?
Or perhaps can I just submit a PR that un-deprecates this perfectly good functionality?
EDIT: I am happy to provide any additional documentation that is deemed necessary.
This is really annoying and seems like it's based out of the assumption that every developer ever is only checking the existence of a file prior to reading/writing in some async context.
Reason being: fs.exists() used an API format that was unlike anything else in our API, and could produce results that were unexpected to those who didn't otherwise know.
fs.access doesn't seem like a replacement given that it also throws when there are any accessibility checks that fail. I don't want/need to do error handling every time I check for a file's existence. I don't think it's fair to call this a replacement.
I'm now given no other option but to either try/catch or make my code async and listen for error events.
That would be correct.
Reacted by Dannii Willis, Ben Johnson, TwistedKap, David Nikdel, Philip Gough, Sai Prashanth Chandramouli, Maël Nison, Hrusikesh Panda, Gary Green, dns and 22 more
OK, close the issue before I can even reply? Awesome!
Reacted by The Jared Wilcurt, Sai Prashanth Chandramouli, Alex, jolaroux, KittenWithHerbs, Tan Yong Heng, Jason, David Wheatley, Justin Hummel, Eliaz Bobadilla and 2 more
Deprecation with this kind of logic/motivation is only going to serve to make this platform less hospitable to people doing things outside of what features core is focused on.
I still don't see any reason why thorough documentation isn't an adequate response to any of the concerns that have been mentioned thus far.
Reacted by Amram E., The Jared Wilcurt, Renato Ribeiro, Sai Prashanth Chandramouli, Alex, Pouya Kary ✨, oxygen, KittenWithHerbs, Jason, Violet Hayes and 4 more
Slapping down an open issue within 20 minutes of its creation is pretty hostile.
The GitHub close issue button is in the same location a cancel button usually is. This isn't uncommon for people to occasionally do. Is the intent not clear since I directly re-opened it? :/
Reacted by Chris Foster, Gavin Lynch, Nicolas Badia, Logan Volkers, Josh Hunt, Rusty Toms, Michał Gołębiowski-Owczarek, Albin Larsson, Jesper Gustafsson, Itamar Schen and 2 more
Reacted by Jesper Gustafsson, William Lauzé and Polyana Fontes
If you're concerned about having to do a try-catch everywhere for fs.accessSync(), why not just make your own wrapper function(s)?:
varfs=require('fs');functionexistsSync(filename){try{fs.accessSync(filename);returntrue;}catch(ex){returnfalse;}}functionexists(filename,cb){fs.access(filename,cb);// or if want exactly the same old API://fs.access(function(err) { cb(err ? false : true); });}
or why not leave the wrapper the way it is and let me continue to use fs.existsSync?
That same thinking can be applied to just adding more and more sugar to core too. There is plenty discussion in the issues I liked above. At minimum, it wasn't particularly perfect, but it wasn't broken either.
Not all flags work on Windows (e.g. O_NOATIME) but most of them do.
It's an undocumented but pretty stable feature. The mode strings themselves are implemented in terms of O_flag constants, e.g., 'a' is shorthand for O_APPEND | O_CREAT | O_WRONLY.
Was just about to open an issue on this. Documentation is unclear about access being a replacement. I think the real issue here is how the not found is communicated. If access/stat are to be used for an existent check, then an exception on not found is too severe. Wouldn't returning that it's not FRWX sufficient?
fs.exists is really necessary. If the api is broken can we fix it rather than deprecate it? Or otherwise, can we provide an option for fs.access, if the second parameter mode === fs.E_OK then do not throw the error and returns the boolean?
TBH I understand wanting such a simple API, but the problem is it's not actually that simple. Take the following example where directory b is a symlink back to a:
Error: ELOOP: too many symbolic links encountered, access './a/b/[...]/a/c
at Error (native)
at Object.fs.accessSync (fs.js:203:11)
Is node also supposed to add the logic of checking for ELOOP and running the path through fs.realpath() to get around this issue? If so then I'd expect node to do it's best to compensate for any platform specific issues in the API. Here things get a bit hairy, and suddenly an API at first glance was one line becomes more complex. Enough, IMO, to merit its own module (there are commonly used smaller modules out there).
@trevnorris Your accessSync example is pretty funky! Luckily, we already know what the right thing to do with that is: existsSync returns false in that case. LGTM, so let's just undeprecate that.
Just for reference I looked up how other languages/runtimes do this:
Python 3 (uses stat, "if stat fails, file is assumed not to exist" -method):
# Does a path exist?# This is false for dangling symbolic links on systems that support them.defexists(path):
"""Test whether a path exists. Returns False for broken symbolic links"""try:
os.stat(path)
exceptOSError:
returnFalsereturnTrue
Java (JDK 8) (uses stat, "if stat fails, file is assumed not to exist" -method):
PHP (uses stat, "if stat fails, file is assumed not to exist" -method):
Snippet from (filestat.c):
/* {{{ proto bool file_exists(string filename) Returns true if filename exists */FileFunction(PHP_FN(file_exists), FS_EXISTS)
...
case FS_EXISTS:
RETURN_TRUE;
Go (uses stat with additional library function to test returned error for file existence clues):
if_, err:=os.Stat("./thefile.ext"); err!=nil {
ifos.IsNotExist(err) {
// file does not exist
} else {
// other error
}
}
Go language approach is the most interesting: they provide standard stat and then have two separate core library convenience functions for determining if returned error indicates file existence or non-existence os.IsExists(err) and os.IsNotExists(err).
With exception of Go language, most common method for implementing "file exists" test seems to be just running stat and assuming file existence if anything / no error is returned.
we already know what the right thing to do with that is: existsSync returns false in that case.
Not exactly. fs.realpath() should resolve the symbolic links to a path that fs.access() can handle (there's a bug in v6 where that doesn't work, for which I'm working on). So if the user got ELOOP they could then call the operation again with fs.access(fs.realpath(path));. Simply returning false would be technically incorrect.
When loaded the module polyfills fs.exists to support both original Node.js callback style and standard error first callback style in a backward compatible way.
This may offer solution to those having issues with the callback(boolean) not working with libraries expecting functions with nodeback standard callback.
Activity
Fishrock123 commentedon May 2, 2015
That's not quite how it is.
See
fs.exists()in the docs .. it's been replaced byfs.access()See #114 for more reference.
Fishrock123 commentedon May 2, 2015
Reason being:
fs.exists()used an API format that was unlike anything else in our API, and could produce results that were unexpected to those who didn't otherwise know.affinity-matrix commentedon May 2, 2015
fs.access doesn't seem like a replacement given that it also throws when there are any accessibility checks that fail. I don't want/need to do error handling every time I check for a file's existence. I don't think it's fair to call this a replacement.
Fishrock123 commentedon May 2, 2015
That would be correct.
affinity-matrix commentedon May 2, 2015
OK, close the issue before I can even reply? Awesome!
affinity-matrix commentedon May 2, 2015
Deprecation with this kind of logic/motivation is only going to serve to make this platform less hospitable to people doing things outside of what features core is focused on.
I still don't see any reason why thorough documentation isn't an adequate response to any of the concerns that have been mentioned thus far.
affinity-matrix commentedon May 2, 2015
I'm also pretty concerned at the realization that this is how we're treating issues created around valid questions/concerns.
Slapping down an open issue within 20 minutes of its creation is pretty hostile.
Fishrock123 commentedon May 2, 2015
Original discussion can be found at nodejs/node-v0.x-archive#8418 & #103
Fishrock123 commentedon May 2, 2015
The GitHub close issue button is in the same location a cancel button usually is. This isn't uncommon for people to occasionally do. Is the intent not clear since I directly re-opened it? :/
mscdex commentedon May 2, 2015
If you're concerned about having to do a try-catch everywhere for
fs.accessSync(), why not just make your own wrapper function(s)?:affinity-matrix commentedon May 2, 2015
or why not leave the wrapper the way it is and let me continue to use fs.existsSync? 😸
Fishrock123 commentedon May 2, 2015
That same thinking can be applied to just adding more and more sugar to core too. There is plenty discussion in the issues I liked above. At minimum, it wasn't particularly perfect, but it wasn't broken either.
192 remaining items
bnoordhuis commentedon Jun 5, 2016
Not all flags work on Windows (e.g. O_NOATIME) but most of them do.
It's an undocumented but pretty stable feature. The mode strings themselves are implemented in terms of O_flag constants, e.g.,
'a'is shorthand forO_APPEND | O_CREAT | O_WRONLY.neuroscr commentedon Jun 14, 2016
Was just about to open an issue on this. Documentation is unclear about access being a replacement. I think the real issue here is how the not found is communicated. If access/stat are to be used for an existent check, then an exception on not found is too severe. Wouldn't returning that it's not FRWX sufficient?
yf-hk commentedon Jun 25, 2016
fs.existsis really necessary. If the api is broken can we fix it rather than deprecate it? Or otherwise, can we provide an option for fs.access, if the second parametermode===fs.E_OKthen do not throw the error and returns the boolean?ChALkeR commentedon Jun 25, 2016
@andyhu Once again:
fs.existsdoesn't do what one might think it's doing judging by its name, and that is a problem.Just use
fs.accessas a replacement, it does exactly the same for allfs.existsusecases (except for having the correct callback signature).trevnorris commentedon Jun 27, 2016
Seems at this point the ask is for an API that does:
TBH I understand wanting such a simple API, but the problem is it's not actually that simple. Take the following example where directory
bis a symlink back toa:Which will result in the following:
Is node also supposed to add the logic of checking for
ELOOPand running the path throughfs.realpath()to get around this issue? If so then I'd expect node to do it's best to compensate for any platform specific issues in the API. Here things get a bit hairy, and suddenly an API at first glance was one line becomes more complex. Enough, IMO, to merit its own module (there are commonly used smaller modules out there).dfabulich commentedon Jun 28, 2016
I filed PR #7455 to improve the performance of
existsSyncbeyond what's possible in pure JS (by avoiding throwing an ignored exception).dfabulich commentedon Jun 28, 2016
@trevnorris Your
accessSyncexample is pretty funky! Luckily, we already know what the right thing to do with that is:existsSyncreturnsfalsein that case. LGTM, so let's just undeprecate that.imyller commentedon Jun 28, 2016
Just for reference I looked up how other languages/runtimes do this:
Python 3 (uses
stat, "if stat fails, file is assumed not to exist" -method):Java (JDK 8) (uses
stat, "if stat fails, file is assumed not to exist" -method):Perl (uses
stat,-e(exists) op is 1/true if stat has returned any results, false otherwise)PHP (uses
stat, "if stat fails, file is assumed not to exist" -method):Snippet from (filestat.c):
Go (uses
statwith additional library function to test returned error for file existence clues):Go language approach is the most interesting: they provide standard
statand then have two separate core library convenience functions for determining if returned error indicates file existence or non-existenceos.IsExists(err)andos.IsNotExists(err).With exception of Go language, most common method for implementing "file exists" test seems to be just running
statand assuming file existence if anything / no error is returned.trevnorris commentedon Jun 28, 2016
@dfabulich
Not exactly.
fs.realpath()should resolve the symbolic links to a path thatfs.access()can handle (there's a bug in v6 where that doesn't work, for which I'm working on). So if the user gotELOOPthey could then call the operation again withfs.access(fs.realpath(path));. Simply returningfalsewould be technically incorrect.imyller commentedon Jul 25, 2016
For those interested:
I've published a userland module
fs-exists-nodebackhttps://github.com/imyller/node-fs-exists-nodeback
When loaded the module polyfills
fs.existsto support both original Node.js callback style and standard error first callback style in a backward compatible way.This may offer solution to those having issues with the
callback(boolean)not working with libraries expecting functions with nodeback standard callback.Fishrock123 commentedon Oct 5, 2016
I think 7b5ffa4 should fix / address this.
It undeprecates
existsSync()and keeps the inconsistent-callbackexists()deprecated.fs,doc: undeprecate existsSync
fs,doc: undeprecate existsSync
fs,doc: undeprecate existsSync