Asked  7 Months ago    Answers:  5   Viewed   224 times

I need to setup an application that watches for files being created in a directory, both locally or on a network drive.

Would the FileSystemWatcher or polling on a timer would be the best option. I have used both methods in the past, but not extensively.

What issues (performance, reliability etc.) are there with either method?

 Answers

11

I have seen the file system watcher fail in production and test environments. I now consider it a convenience, but I do not consider it reliable. My pattern has been to watch for changes with the files system watcher, but poll occasionally to catch missing file changes.

Edit: If you have a UI, you can also give your user the ability to "refresh" for changes instead of polling. I would combine this with a file system watcher.

Tuesday, June 1, 2021
 
lena
answered 7 Months ago
42

A typical problem of this approach is that the file is still being copied while the event is triggered. Obviously, you will get an exception because the file is locked during copying. An exception is especially likely on large files.

As a workaround you could first copy the file and then rename it and listen to the renaming event.

Or another option would be to have a while loop checking whether the file can be opened with write access. If it can you will know that copying has been completed. C# code could look like this (in a production system you might want to have a maximum number of retries or timeout instead of a while(true)):

/// <summary>
/// Waits until a file can be opened with write permission
/// </summary>
public static void WaitReady(string fileName)
{
    while (true)
    {
        try
        {
            using (Stream stream = System.IO.File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
            {
                if (stream != null)
                {
                    System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} ready.", fileName));
                    break;
                }
            }
        }
        catch (FileNotFoundException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        catch (IOException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        catch (UnauthorizedAccessException ex)
        {
            System.Diagnostics.Trace.WriteLine(string.Format("Output file {0} not yet ready ({1})", fileName, ex.Message));
        }
        Thread.Sleep(500);
    }
}

Yet another approach would be to place a small trigger file in the folder after copying is completed. Your FileSystemWatcher would listen to the trigger file only.

Wednesday, June 9, 2021
 
SilverHorn
answered 6 Months ago
26

It sounds like you want to write to your log file when your log file is read externally, or something to that effect. If that is the case, there is a NotifyFilters value, LastAccess. Make sure this is set as one of the flags in your FileSystemWatcher.NotifyFilter property. A change in the last access time will then fire the Changed event on FileSystemWatcher.

Currently, FileSystemWatcher does not allow you to directly differentiate between a read and a change; they both fire the Changed event based on the "change" to LastAccess. So, it would be infeasible to watch for reads to a large number of files. However, you seem to know which file you're watching, so if you had a FileInfo object for that file, and FileSystemWatcher fired its Changed event, you could get a new one and compare LastAccessTime values. If the access time changed, and LastWriteTime didn't, your file is only being read.

Now, in simplest terms, changes you make to the file while it is being read are not going to immediately show up in the other app, nor are you going to be able to "get there first", lock the file and write to it before they see it. So, you cannot use FileSystemWatcher to "intercept" a read request and show the content you want that app to see. The only way the user of another application can see what you just wrote is if the application is also watching the file and re-loads the file. That will fire another Changed event, causing an infinite loop as long as the other application continues to reload the file.

You will also get a Changed event for a read and a write. Opening a file in a text editor (virtually any will do), making some changes, then saving will fire two Changed events if you're looking for changes to Last Access Time. The first one will go off when the file is opened by the editor; at that time, you may not be able to tell that a write will happen, so if you are looking for pure read-only accesses to the file then you're SOL.

Saturday, June 26, 2021
 
Exoon
answered 6 Months ago
45

It's enough if you create a watcher for each directory (and optionally, you can have the watcher to monitor a whole directory tree.) You can then use the events to compare the changed files with the list of files you are interested in.

I would suggest you make some kind of "nanny" class for the watchers to ensure you doesn't dispose active watchers, or create duplicate. Just a tip :)

Btw, yes, there's a limit, you can't create infinite watchers. In specific scenarios that can be a problem, but most likely, that's not the case for you

Thursday, August 26, 2021
 
chugadie
answered 3 Months ago
47

You want to take a look at FileSystemEntity.watch() method. However due to platform differences some platforms provide better support than others. In particular, on Windows you can only watch a Directory, and not just an individual file. On Linux you can watch Files or Directories but not recursively watch Directories. And MacOS supports all of the above.

There is also a watcher package on Pub. This supports polling (periodically check if the file has changed) if the file system does not allow watching.

Saturday, November 27, 2021
 
Sethunath
answered 4 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share