122

I'm trying to write a node.js script that watches for changes in a directory of files, and then prints the files that are changed. How can I modify this script so that it watches a directory (instead of an individual file), and prints the names of the files in the directory as they are changed?

var fs = require('fs'),
    sys = require('sys');
var file = '/home/anderson/Desktop/fractal.png'; //this watches a file, but I want to watch a directory instead
fs.watchFile(file, function(curr, prev) {
    alert("File was modified."); //is there some way to print the names of the files in the directory as they are modified?
});
Oleg
  • 9,341
  • 2
  • 43
  • 58
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • I wonder if this is relevant: http://stackoverflow.com/questions/12063266/how-do-you-watch-multiple-files-but-only-run-task-on-changed-file-in-grunt-js (I'm not familiar with gruntjs, though - I hope there are other solutions.) – Anderson Green Dec 04 '12 at 02:16
  • Perhaps something like node-inotify-plusplus would be useful: http://stackoverflow.com/questions/5877263/monitoring-directory-for-changes-potential-high-memory – Anderson Green Dec 04 '12 at 02:32
  • What OS are you running? This matters as the low level mechanisms for watching a file are vastly different as Unix/Linux uses `inotify`, OSX uses `FSWatch` and I have no idea about Windoze but I'm sure Google could tell you. – srquinn Dec 04 '12 at 05:15
  • 1
    Though I originally used the plain `node-inotify` in my project, I eventually switched to `node-inotify-plusplus` because who doesn't like abstractions? =) – srquinn Dec 04 '12 at 05:31

3 Answers3

196

Try Chokidar:

var chokidar = require('chokidar');

var watcher = chokidar.watch('file or dir', {ignored: /^\./, persistent: true});

watcher
  .on('add', function(path) {console.log('File', path, 'has been added');})
  .on('change', function(path) {console.log('File', path, 'has been changed');})
  .on('unlink', function(path) {console.log('File', path, 'has been removed');})
  .on('error', function(error) {console.error('Error happened', error);})

Chokidar solves some of the crossplatform issues with watching files using just fs.

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
mtsr
  • 3,092
  • 1
  • 14
  • 21
  • 9
    Does it handle subfolders? – Stepan Yakovenko Feb 16 '17 at 13:56
  • 3
    One problem with this - When I copy a large file. The add event gets triggered immediately and then I get hundreds of change events as the file copy progresses. Any way to trigger only one event for when the file copy ends ? – Curious101 Apr 11 '19 at 20:07
  • 14
    @Curious101, have you tried adding `awaitWriteFinish: true`? It's false by default. – cs_pupil Apr 12 '19 at 04:00
  • I want to ask one thing, is it worthy to use on large file system, you can say i want to monitor `/home/terabyte`. Well not recursive – tbhaxor May 28 '19 at 04:28
  • Can I use this Create React App? Not in production ofcourse. – Mert Aug 16 '21 at 13:11
70

Why not just use the old fs.watch? Its pretty straightforward.

fs.watch('/path/to/folder', (eventType, filename) => {
console.log(eventType);
// could be either 'rename' or 'change'. new file event and delete
// also generally emit 'rename'
console.log(filename);
})

For more info and details about the options param, see Node fs Docs

Kaushik Evani
  • 1,154
  • 9
  • 17
  • 14
    Note of warning, I've tested this on my mac, and this code only detects that folder level and not any subdirectories for changes, so be sure so be sure to add the option to watch recursively as the second parameter; see the docs linked above – OzzyTheGiant Nov 23 '17 at 01:25
  • 2
    Added Note to @OzzyTheGiant's Note: The recursive option is only supported on macOS and Windows. – Kaushik Evani Nov 24 '17 at 07:27
  • Node's `fs.watch()` is a bit clunky, and you have to build your won debounce implementation. – mwieczorek Apr 21 '18 at 15:50
  • @mwieczorek What does 'debounce' mean? – Thomas Jay Rush Dec 10 '19 at 09:15
  • 6
    @ThomasJayRush a mechanism that allows for a certain amount of time to pass between and event and the action to take place, so if an event fires twice, the action is only invoked once. It's an engineering term where a physical button would trigger electric current, but the button would "bounce" one or more times, creating multiple spikes in the current where only one was desired - which can be applied to programming as well - especially JS. https://medium.com/@jamischarles/what-is-debouncing-2505c0648ff1 – mwieczorek Dec 12 '19 at 08:21
  • 1
    please use chokidar as this api is not consistent across platforms. – Sandeep Gahlawat Dec 09 '20 at 12:43
16

try hound:

hound = require('hound')

// Create a directory tree watcher.
watcher = hound.watch('/tmp')

// Create a file watcher.
watcher = hound.watch('/tmp/file.txt')

// Add callbacks for file and directory events.  The change event only applies
// to files.
watcher.on('create', function(file, stats) {
  console.log(file + ' was created')
})
watcher.on('change', function(file, stats) {
  console.log(file + ' was changed')
})
watcher.on('delete', function(file) {
  console.log(file + ' was deleted')
})

// Unwatch specific files or directories.
watcher.unwatch('/tmp/another_file')

// Unwatch all watched files and directories.
watcher.clear()

It will execute once file was change

Sharathi RB
  • 867
  • 2
  • 9
  • 24