NodeJs: fs.stat() or fs.access() to check if a folder exists?

BenSower picture BenSower · Feb 4, 2019 · Viewed 7.8k times · Source

I am currently trying to figure out the "correct" way to check if a local folder exists, before saving a file into it and am a little bit confused by the nodejs docs.

fs.exists() is deprecated and you should use fs.stat() or fs.access(). So far so good.

fs.stat():

Using fs.stat() to check for the existence of a file before calling fs.open(), fs.readFile() or fs.writeFile() is not recommended. Instead, user code should open/read/write the file directly and handle the error raised if the file is not available.

This states, that I should just try to write, catch the error, create the folder, and try again. Also fine by me, even though I am moving/renaming the file , so I don't directly use one of the three mentioned functions.

then, the doc says:

To check if a file exists without manipulating it afterwards, fs.access() is recommended.

Since I am not really modifying the file, but "only" it's content, one might argue that this is the way to go.

But then again, the fs.access() documentation goes into detail why that's a bad idea, too:

Using fs.access() to check for the accessibility of a file before calling fs.open(), fs.readFile() or fs.writeFile() is not recommended. Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible.

Yadda yadda yadda, there are already somewhat related questions (here, or here), but is there any official info on the "best practice" that's not more than two years old?

Answer

Yudhistira Arya picture Yudhistira Arya · Jan 11, 2020

I guess the documentation suggest to use fs.access to check if a file exists when there's no manipulation afterwards is because it's a lower level and simple API with a single purpose of checking file-access metadata (which include whether a file exists or not). A simpler API might be little bit better too in term of performance as it may just be a straightforward mapping to the underlying native code.(NOTE: I haven't do any benchmark, take my statement with grain of salt).

fs.stat provide a higher level of abstraction compared to fs.access. It returns information beyond file-access.

import {promises as fs} from "fs";
import * as oldfs from "fs";

(async function() {
    // fs.stat has higher level abstraction
    const stat = await fs.stat(__dirname);
    console.log(stat.isDirectory());
    console.log(stat.isFile());
    console.log(stat.ctime);
    console.log(stat.size);

    try {
        // fs.access is low level API, it throws error when it doesn't match any of the flags
        // is dir exists? writable? readable?
        await fs.access(__dirname, oldfs.constants.F_OK | oldfs.constants.W_OK | oldfs.constants.R_OK);
    } catch (error) {
        console.log(`${__dirname} is not exists / writable / readable`);
    }
})();