How it works...

The fs module has two watch methods, fs.watch and fs.watchFile.

Whilst fs.watch is more responsive and can watch entire directories, recursively, it has various consistency and operational issues on different platforms (for instance, the inability to report filenames on macOs; it may report events twice, or not report them at all).

Instead of using an OS relevant notification subsystem (such as fs.watch), the fs.watchFile function polls the file at a specified interval (defaulting to 5,007 milliseconds).

The listener function (supplied as the last argument to fs.watchFile), is called every time the file is altered in some way. The listener takes two arguments. The first argument is a stats object (as provided by fs.stat; see the Fetching metadata recipe) of the file in its current state, while the second argument is a stats object of the file in its previous state.

We use these objects along with our three lambda functions, created, missing, and updated to infer how the file has been altered.

The created function checks whether the birthtime (time of the file creation) is less than the polling interval, and if so, then it's likely the file was created.

We introduce certainty by setting an exists variable and tracking the file's existence in our listener function. So our created function checks this variable first; if the file is known to exist, then it can't have been created. This caters to situations where a file is updated multiple times within the polling interval period and ensures the first file alteration event is interpreted as a change, whilst subsequent triggers are not (unless the file was detected as removed).

When fs.watchFile attempts to poll a non-existent (or at least, inaccessible) file, it signals this eventuality by setting the birthtime, mtime, atime, and ctime to zero (the Unix epoch). Our missing function checks for this by bitwise OR-ing all four dates; this implicitly converts the dates to numerical values and will result either in 0 or some other number (if any of the four values are non-zero). This in turn is converted to a Boolean; if the result is 0, missing returns true; otherwise, it returns false.

The mtime is the time since the file data was last changed. Comparing the mtime of the file before and after the event allows us to differentiate between a change where the file content was updated, and a change where file metadata was altered.

The updated function compares the mtime on the previous and current stat objects. If they're not the same, then the file content must have been changed; if they are the same, then the file was modified in some other way (for instance, a chmod).

Our listener function checks these utility functions and then updates the exists variable and logs out messages accordingly.