Checking file existence

A fairly common task in systems and server side programming, is checking whether a file exists or not.

There is a method, fs.exists (and its sync cousin, fs.existsSync), which allows us to perform this very action. However, it has been deprecated since Node version 4, and therefore isn't future-safe.

A better practice is to use fs.access (added when fs.exists was deprecated).

By default fs.access checks purely for file visibility, which is essentially the equivalent of checking for existence.

Let's write a file called check.js; we can pass it a file and it will tell us whether the file exists or not:

const fs = require('fs') 

const exists = (file) => new Promise((resolve, reject) => {
fs.access(file, (err) => {
if (err) {
if (err.code !== 'ENOENT') { return reject(err) }
return resolve({file, exists: false})
}
resolve({file, exists: true})
})
})

exists(process.argv[2])
.then(({file, exists}) => console.log(`"${file}" does${exists ? '' : ' not'} exist`))
.catch(console.error)
Promises
For extra fun here (because the paradigm fits well in this case), we used the ES2015 native Promise abstraction. Find out more about promises at https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise . In general, we tend to use a minimal subset of ES2015 ( ES6) throughout so we can focus more on using Node and less on syntax, avoiding either extra discourse or potential confusion. We should also note that Promises are currently a poor choice for implementing production server logic in Node, due to (standards specified) opaque behaviors (error swallowing, asynchronous stack unwinding) leading to difficulties in production root cause analysis.

Now if we run the following:

$ node check.js non-existent-file 
"non-existent-file" does not exist

But if we run:

$ node check.js check.js 
"check.js" does exist

The fs.access method is more versatile than fs.exists. It can be passed different modes (fs.F_OK (default), fs.R_OK, fs.W_OK, and fs.X_OK) to alter access checks being made. The mode is a number, and the constants of fs (ending in _OK) are numbers, allowing for a bitmask approach.

For instance, here's how we can check if we have permissions to read, write, and execute a file (this time with fs.accessSync):

fs.access('/usr/local/bin/node', fs.R_OK | fs.W_OK | fs.X_OK, console.log) 

If there's a problem accessing, an error will be logged, if not, null will be logged.

Modes and bitmasks
For more on fs.access, see the docs at https://nodejs.org/api/fs.html#fs_fs_access_path_mode_callback. To learn about bitmasks, check out https://abdulapopoola.com/2016/05/30/understanding-bit-masks/