See Also edit
- directory notification package in Tcl
- for Linux
- Tcl-Inotify
- an efficient Linux-only solution
- TWAPI
- has the begin_filesystem_monitor/cancel_filesystem_monitor [1] functions to allow you to monitor file system changes by registering a callback. Like the rest of TWAPI, WIndoes NT 4.0 and later only. See [2] for an example.
- watchman
- A service that can watch for changes on Linux, OS X, FreeBSD, OpenBSD and Illumos/Solaris and abstracts away the differences between those platforms. It can be controlled using the command line or a JSON API spoken over a UNIX socket. In both cases watchman returns JSON output.
- filewatcherd
- FreeBSD daemon
Generic Solution edit
Not a complete solution, but on the systems where [file mtime] returns the last update of a directory/file a reasonably efficient solution is just glob all files in a directory tree and storing their mtime. If you are only interested in create/rename/delete events (like most UIs are) you only need to call [file mtime $dir] to see if a file has been created/renamed/deleted since you last checked. Doing this every two seconds gives good interactive response in most cases (for UIs)US: Just to emphasize: This does not work for write/update operations on a file!namespace eval fschanges { if {0} { #if debugging: interp alias {} [namespace current]::dputs {} puts } else { proc dputs {args} { } } variable watchId 0 proc watch {file_or_dir} { variable watchId incr watchId upvar [namespace current]::watch$watchId watching if {[info exists [namespace current]::watch$watchId]} { array unset [namespace current]::watch$watchId } set watching(watching) [list] if {[file isdir $file_or_dir]} { addDir watch$watchId $file_or_dir } else { add watch$watchId $file_or_dir } #set initial scan time set watching(last) [clock seconds] return watch$watchId } proc add {id name} { dputs "add $name" upvar [namespace current]::$id watching if {[info exists watching(watch.$name)]} { dputs "add exists $name" #no watching twice! return } lappend watching(watching) $name [file isdir $name] #and determine initial time (if any) if {[file exists $name]} { set itime [file mtime $name] } else { set itime 0 } set watching(watch.$name) $itime return $name } proc addDir {id dir} { dputs "Add dir $dir" upvar [namespace current]::$id watching if {[info exists watching(watch.$dir)]} { dputs "Adddir exists $dir" #no watching twice! return } #puts "Add dir $dir" lappend new [add $id $dir] #puts "glob: [glob -nocomplain -path $dir/ *]" foreach file [glob -nocomplain -path $dir/ *] { if {[file isdir $file]} { dputs "Recurse into $file" set new [concat $new [addDir $id $file]] } else { lappend new [add $id $file] } } return $new } proc newfiles {id time} { upvar [namespace current]::$id watching set newer [list] foreach {file isdir} $watching(watching) { if {$watching(watch.$file) >= $time} { lappend newer $file } } return $newer } proc changes {id} { upvar [namespace current]::$id watching set changes [list] set new [list] #puts $watching(watching) foreach {file isdir} $watching(watching) { #puts "$isdir && [file mtime $file] > $watching(watch.$file)" if {$isdir && [file exists $file] && [file mtime $file] > $watching(watch.$file)} { set watching(watch.$file) [file mtime $file] lappend changes $file update foreach item [glob -nocomplain -dir $file *] { if {![info exists watching(watch.$item)]} { if {[file isdir $item]} { set new [concat $new [addDir $id $item]] } else { lappend new [add $id $item] } } } } } foreach item $new { lappend changes $item created } return $changes } namespace export watch changes newfiles } package provide fschanges 0.5Sample usage
package require fschanges namespace import fschanges::* #watch a directory: set w [watch /tmp] puts "Files created within the last hour: [newfiles $w [expr [clock seconds]-3600]]" exec touch /tmp/testfile #Show the new file and directory update: puts [changes $w] file delete -force /tmp/testfile #file deletions are not noted (yet) but it will show an updated directory. puts [changes $w]
Platform specific Which platforms can do this? It would be nice to create a (core?) extension to do this.
- Windows 95, 98, ME, NT 2000, XP: Yes, [FindFirstChangeNotification]() and NTFS can do [file mtime $dir]
- Windows CE: unknown but also likely to support FindFirstChangeNotification.
- Linux <2.2: Unknown, but ext2 can do [file mtime $dir]
- Linux 2.2+: Yes, see linux/Documentation/dnotify.txt using fcntl(fd, F_NOTIFY,DN_MODIFY|DN_CREATE|DN_MULTISHOT); See directory notification package in Tcl for more.
- FreeBSD: Yes, [kqueue]: http://people.freebsd.org/~jlemon/papers/kqueue.pdf
- OpenBSD: Supports kqueue in version 3.1 (unknown when first supported)/
- (Other)BSD: Same as FreeBSD? NetBSD supports kqueue since 2.0
- Classic Mac: Unknown
- MacOSX: Supports kqueue starting with 10.3
- Solaris: stevel thought so.
- HP-UX: unknown
- irix: yes. there's a file monitor.
- dec: unknown
- others: ???
elfring 2003-08-26: How do you think about the tool "File Alteration Monitor and Inode Monitor" (http://oss.sgi.com/projects/fam/links.html)? I do not know when a TCL programming interface will be available for it.ps 2003-08-27: Well, by the looks of it, the IMon project is complementary to the DNotify stuff, and will probably be used if we get round to make a Tcl package.elfring 2003-11-01: Can the function library "liboop" help to dispatch file events easier?
MHo: See ffcn for several (incomplete) solutions. I think, the drawback of tcl-only-solutions are that they are based on polling, whereas the windows-apis are event-based. Because the MS-APIs are, as usual, pure horror, TWAPI seems to be the most elegant way, but because TWAPI is a big monolithic block, the code blows up.APN: MHo, could you explain what you mean by the code blows up? I'd like to fix any bugs in TWAPI. MHo: sorry, perhaps this was the wrong phrase. I meant that: the code one have to write is usually clear and small, because the commands of TWAPI are very powerfull. What I forgot to mention is that I almost always deploy programs as starpacks (=executables). And the twapi dll is very heavy in size.