10

I find the .Net FileSystemWatcher class really handy for writing utilities that automatically come to life when files show up in their watched folders. Is there any equivalent to this functionality in the *nix world that would allow me to watch a folder (and possibly all of its subdirectories)?

Edit: Preferably this will be something that doesn't require kernel patches.

Luke
  • 18,585
  • 24
  • 87
  • 110

6 Answers6

15

I would like to share my observations using FileSystemWatcher in Mono in Ubuntu 10.10. Here is a very simple implementation of FileSystemWatcher in C#

using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.IO;
using System.Reflection;

namespace FileSystemWatcherSandbox
{
    public class Program
    {
        static void Main(string[] args)
        {
            foreach(DictionaryEntry de in Environment.GetEnvironmentVariables())
            {
                Console.WriteLine("{0} = {1}",de.Key,de.Value);
            }
            string basePath = AppDomain.CurrentDomain.BaseDirectory;
            Console.WriteLine("watching: {0}", basePath);
            FileSystemWatcher fsw = new FileSystemWatcher(basePath);
            fsw.Changed += new FileSystemEventHandler(fsw_Changed);
            fsw.Created += new FileSystemEventHandler(fsw_Created);
            fsw.Deleted += new FileSystemEventHandler(fsw_Deleted);
            fsw.Error += new ErrorEventHandler(fsw_Error);
            fsw.Renamed += new RenamedEventHandler(fsw_Renamed);
            fsw.EnableRaisingEvents = true;
            fsw.IncludeSubdirectories = true;
            while (true)
            {
                WaitForChangedResult result = fsw.WaitForChanged(WatcherChangeTypes.All,10000);
                Console.WriteLine(result.TimedOut ? "Time out" : "hmmm");
            }
        }

        static void fsw_Renamed(object sender, RenamedEventArgs e)
        {
            Console.WriteLine("({0}): {1} | {2}", MethodInfo.GetCurrentMethod().Name, e.ChangeType, e.FullPath);
        }

        static void fsw_Error(object sender, ErrorEventArgs e)
        {
            Console.WriteLine("({0}): {1}", MethodInfo.GetCurrentMethod().Name, e.GetException().Message);
        }

        static void fsw_Deleted(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine("({0}): {1} | {2}", MethodInfo.GetCurrentMethod().Name, e.ChangeType, e.FullPath);
        }

        static void fsw_Created(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine("({0}): {1} | {2}", MethodInfo.GetCurrentMethod().Name, e.ChangeType, e.FullPath);
        }

        static void fsw_Changed(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine("({0}): {1} | {2}", MethodInfo.GetCurrentMethod().Name, e.ChangeType, e.FullPath);
        }
    }
}

This code was tested and works on both Windows XP and Ubuntu 10.10. However, I would like to point out that under Ubuntu 10.10 (possibly earlier versions as well), the FileSystemWatcher behaves uniquely.
If the directory that is being watched does not contain subdirectories, then invoking a FileSystemWatcher with the IncludeSubdirectories property set to true will result in the FileSystemWatcher ignoring events. However, if there are subdirectories in the target directory, then IncludeSubdirectories set to true will work as expected.
What will always work is if IncludeSubdirectories is set to false. In this instance, the FileSystemWatcher will only be watching the target directory.
I hope this is useful for programmers that would like to utilize Mono across different operating systems and invoke the FileSystemWatcher type.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
J Mills
  • 1,730
  • 1
  • 19
  • 16
14

That would be Gamin the File Alteration Monitor or Inotify.

Edit: Mono does have Gamin bindings - in fact, its implementation of FileSystemWatcher uses Gamin. https://www.mono-project.com/docs/faq/technical/#what-are-the-issues-with-filesystemwatcher.

What are the issues with FileSystemWatcher?

The Mono implementation of FileSystemWatcher has a number of backends, the most optimal one, the one with fewer dependencies is the inotify-backend (available in Mono 1.1.17 and newer versions).

With this backend the kernel provides Mono with updates on any changes to files on the file system but it requires an inotify-enabled kernel, which only newer Linux distributions ship.

In older Linux systems, you must have installed FAM or Gamin (it will work with either one). You might need the -devel packets installed.

For the *BSD family, there’s a Kqueue based implementation that will be used when detected at runtime.

If none of the above work, Mono falls back to polling the directories for changes, which far from optimal.

Community
  • 1
  • 1
Mihai Limbășan
  • 64,368
  • 4
  • 48
  • 59
6

As has already being said, Mono has the class "System.IO.FileSystemWatcher", this is the relevant link: http://www.go-mono.com/docs/monodoc.ashx?link=T%3aSystem.IO.FileSystemWatcher

"Mono's implementation of the FileSystemWatcher has multiple backends. This is necessary because not all operating systems supported by Mono have all the features necessary to provide the functionality expected by applications.

If the operating system kernel supports watching directories (inotify on Linux, KEvents on BSD or OSX) that feature is used; Otherwise it falls back to using the Gamin or FAM libraries (these libraries provide an API to monitor directories) and if none of those features are available, Mono will poll every 750 milliseconds the directories watched.

You can force the polling behavior (instead of using the kernel support) by setting the MONO_MANAGED_WATCHER environment variable before executing your application. This might be useful for filesystems that do not support inotify and still require polling to detect changes."

Jordij
  • 158
  • 2
2

Yes, dnotify and inotify.

I don't know if Mono has these wrapped, but it would be worth checking.

Barry Kelly
  • 41,404
  • 5
  • 117
  • 189
  • I've read elsewhere that the FileSystemWatcher doesn't work with linux filesystems when running in a Mono environment. Thanks though. – Luke Nov 27 '08 at 17:25
  • The problem with inotify is, that it's not portable b/c it only exists on linux and not on Unix in general. – André Nov 27 '08 at 17:27
  • Beagle uses inotify, so it's definitely wrapped in Mono somewhere. – Paul Fisher Nov 27 '08 at 17:32
2

If you're using the wonderful QT library (www.qtsoftware.com) it's included as the QFileSystemWatcher.

1

We are yet to test that this is a suitable alternative in our situation, but it seems that Microsoft introduced PhysicalFileProvider some time ago.

It has a UsePollingFileWatcher property specifically for this kind of problem.

Then for the file watching, it seems you want the Watch method.

The documentation is currently showing it as not available on certain platforms or target frameworks, but in practice the NuGet package claims to be .NET Standard 2.0 compatible, so that should cover basically everything.

Adam Goodwin
  • 3,951
  • 5
  • 28
  • 33
  • After having looked into this more, it seems it actually isn't very helpful, the class doesn't seem to really tell you about specific changes to files, just that something you're interested in has changed. – Adam Goodwin Jan 23 '23 at 15:17