Check synchronously if file/directory exists in Node.js

前端 未结 15 2131
梦如初夏
梦如初夏 2020-11-22 12:26

How can I synchronously check, using node.js, if a file or directory exists?

相关标签:
15条回答
  • 2020-11-22 13:07

    From the answers it appears that there is no official API support for this (as in a direct and explicit check). Many of the answers say to use stat, however they are not strict. We can't assume for example that any error thrown by stat means that something doesn't exist.

    Lets say we try it with something that doesn't exist:

    $ node -e 'require("fs").stat("god",err=>console.log(err))'
    { Error: ENOENT: no such file or directory, stat 'god' errno: -2, code: 'ENOENT', syscall: 'stat', path: 'god' }
    

    Lets try it with something that exists but that we don't have access to:

    $ mkdir -p fsm/appendage && sudo chmod 0 fsm
    $ node -e 'require("fs").stat("fsm/appendage",err=>console.log(err))'
    { Error: EACCES: permission denied, stat 'access/access' errno: -13, code: 'EACCES', syscall: 'stat', path: 'fsm/appendage' }
    

    At the very least you'll want:

    let dir_exists = async path => {
        let stat;
        try {
           stat = await (new Promise(
               (resolve, reject) => require('fs').stat(path,
                   (err, result) => err ? reject(err) : resolve(result))
           ));
        }
        catch(e) {
            if(e.code === 'ENOENT') return false;
            throw e;
        }
    
        if(!stat.isDirectory())
            throw new Error('Not a directory.');
    
        return true;
    };
    

    The question is not clear on if you actually want it to be syncronous or if you only want it to be written as though it is syncronous. This example uses await/async so that it is only written syncronously but runs asyncronously.

    This means you have to call it as such at the top level:

    (async () => {
        try {
            console.log(await dir_exists('god'));
            console.log(await dir_exists('fsm/appendage'));
        }
        catch(e) {
            console.log(e);
        }
    })();
    

    An alternative is using .then and .catch on the promise returned from the async call if you need it further down.

    If you want to check if something exists then it's a good practice to also ensure it's the right type of thing such as a directory or file. This is included in the example. If it's not allowed to be a symlink you must use lstat instead of stat as stat will automatically traverse links.

    You can replace all of the async to sync code in here and use statSync instead. However expect that once async and await become universally supports the Sync calls will become redundant eventually to be depreciated (otherwise you would have to define them everywhere and up the chain just like with async making it really pointless).

    0 讨论(0)
  • 2020-11-22 13:08

    Looking at the source, there's a synchronous version of path.exists - path.existsSync. Looks like it got missed in the docs.

    Update:

    path.exists and path.existsSync are now deprecated. Please use fs.exists and fs.existsSync.

    Update 2016:

    fs.exists and fs.existsSync have also been deprecated. Use fs.stat() or fs.access() instead.

    Update 2019:

    use fs.existsSync. It's not deprecated. https://nodejs.org/api/fs.html#fs_fs_existssync_path

    0 讨论(0)
  • 2020-11-22 13:08

    0 讨论(0)
  • 2020-11-22 13:09

    Here is a simple wrapper solution for this:

    var fs = require('fs')
    function getFileRealPath(s){
        try {return fs.realpathSync(s);} catch(e){return false;}
    }
    

    Usage:

    • Works for both directories and files
    • If item exists, it returns the path to the file or directory
    • If item does not exist, it returns false

    Example:

    var realPath,pathToCheck='<your_dir_or_file>'
    if( (realPath=getFileRealPath(pathToCheck)) === false){
        console.log('file/dir not found: '+pathToCheck);
    } else {
        console.log('file/dir exists: '+realPath);
    }
    

    Make sure you use === operator to test if return equals false. There is no logical reason that fs.realpathSync() would return false under proper working conditions so I think this should work 100%.

    I would prefer to see a solution that does not does not generate an Error and resulting performance hit. From an API perspective, fs.exists() seems like the most elegant solution.

    0 讨论(0)
  • 2020-11-22 13:11

    fs.exists() is deprecated dont use it https://nodejs.org/api/fs.html#fs_fs_exists_path_callback

    You could implement the core nodejs way used at this: https://github.com/nodejs/node-v0.x-archive/blob/master/lib/module.js#L86

    function statPath(path) {
      try {
        return fs.statSync(path);
      } catch (ex) {}
      return false;
    }
    

    this will return the stats object then once you've got the stats object you could try

    var exist = statPath('/path/to/your/file.js');
    if(exist && exist.isFile()) {
      // do something
    }
    
    0 讨论(0)
  • 2020-11-22 13:12

    Using fileSystem (fs) tests will trigger error objects, which you then would need to wrap in a try/catch statement. Save yourself some effort, and use a feature introduce in the 0.4.x branch.

    var path = require('path');
    
    var dirs = ['one', 'two', 'three'];
    
    dirs.map(function(dir) {
      path.exists(dir, function(exists) {
        var message = (exists) ? dir + ': is a directory' : dir + ': is not a directory';
        console.log(message);
      });
    });
    
    0 讨论(0)
提交回复
热议问题