BanksySan
BanksySan

Reputation: 28560

Is it possible to watch a file, to see when it is being read?

I have a file, it is large, reading it takes a long time and I'd like to have some monitoring to see when it's being written to.

I can solve this quite easily by chucking some logging into the application that it reading it, however I'd like something more agnostic. There are quite a few application that have a similar use case. Monitoring writes should be easy enough as I can watch the last modified date, but reading isn't so easy.

If there any way to passively monitor read and writes to a file?

To clarify: If it can do done in 100% C#, then great, if not then shelling out to some other 'thing', or even resorting to some other language is fine. I don't really mind what the watching bit is written in.

Trying Rahul's Solution

I have set up ithe following test code. It dumps events to the console:

public static void Main()
{
    var taskFactory = new TaskFactory();
    var setup = new Action(() =>
    {
        var setupWatcher =
            new Action<NotifyFilters, string, FileSystemWatcher>((filters, s, watcher) =>
            {
                watcher.EnableRaisingEvents = true;
                watcher.NotifyFilter = filters;
                watcher.Changed += (sender, args) => System.Console.WriteLine(s, args.FullPath, args.ChangeType);
            });


        var lastAccessWatcher = new FileSystemWatcher(BASE_PATH);
        setupWatcher(NotifyFilters.LastAccess,
            "File: {0}\tFilter: LastAccess\tType: {1}", lastAccessWatcher);

        var lastWriteWatcher = new FileSystemWatcher(BASE_PATH);
        setupWatcher(NotifyFilters.LastWrite, "File: {0}\tFilter: LastWrite\tType: {1}",
            lastWriteWatcher);

        var fileNameWatcher = new FileSystemWatcher(BASE_PATH);
        setupWatcher(NotifyFilters.FileName,
            "File: {0}\tFilter: FileName\tType: {1}", fileNameWatcher);

        var directoryNameWatcher = new FileSystemWatcher(BASE_PATH);
        setupWatcher(NotifyFilters.LastWrite, "File: {0}\tFilter: DirectoryName\tType: {1}",
            directoryNameWatcher);
    });

    taskFactory.StartNew(setup);

    while (true)
    {
        Thread.Sleep(10);
    }
}

However, when I open a text file in notepad, no event is thrown by the lastAccessWatcher, whereas, when I save, two events are thrown by the lastWriteWatcher and the directoryNameWatcher, as per below.

File: F:\FileMonitor\New Text Document.txt      Filter: LastWrite       Type: Changed
File: F:\FileMonitor\New Text Document.txt      Filter: LastWrite       Type: Changed
File: F:\FileMonitor\New Text Document.txt      Filter: DirectoryName   Type: Changed
File: F:\FileMonitor\New Text Document.txt      Filter: DirectoryName   Type: Changed

So...

  1. What does trigger 'last access'
  2. Can I actually have any trigger fired when a file is read?

Upvotes: 3

Views: 1263

Answers (4)

In code your task is handled with a filesystem filter driver. Process Monitor application (already mentioned in another answer) includes such driver in pre-built form.

You can write a kernel-mode driver yourself, yet this would probably be an overkill. Then there exists our CallbackFilter - a class library with a pre-created kernel-mode driver included. You write code in C# and catch all filesystem operations before or after they are performed. If your need is short-term, then the evaluation license will work.

Upvotes: 0

Rahul Tripathi
Rahul Tripathi

Reputation: 172628

You can use the FileSystemWatcher class

Listens to the file system change notifications and raises events when a directory, or file in a directory, changes.

You can use the different events

and also read this FileSystemWatcher Tips

An example:

public void MyFileWatcher(string path)
{
    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = path;
    watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
       | NotifyFilters.FileName | NotifyFilters.DirectoryName;
    watcher.Filter = "myFile.txt";
    watcher.Changed += new FileSystemEventHandler(OnChanged);    
    watcher.EnableRaisingEvents = true;
}

private static void OnChanged(object source, FileSystemEventArgs e)
{
   Console.WriteLine(e.FullPath + " " + e.ChangeType);
}

Similarly you can add other event handlers definition.

Also if you want to check the read then you can use the FileInfo.LastAccessTime and FileInfo.Refresh() in a polling loop to get the information of when your file is being read.

Upvotes: 1

ken2k
ken2k

Reputation: 49013

One solution would be to use a Microsoft tool called Process Monitor. It's able to list all CreateFile/ReadFile/WriteFile calls any process does. There are several command line options available:

enter image description here

Upvotes: 1

Ron Beyer
Ron Beyer

Reputation: 11273

For watching writes to the file, the FileSystemWatcher class is the right way to go. However if you want to know if a file is being written, what I would do is get a list of all the open files by process, and monitor when the file is opened and then closed.

There is a CodeProject article that shows how to get the open files by process here.

Upvotes: 2

Related Questions