views:

117

answers:

6

I'm using FileSystemWatcher to check when a file is modified or deleted, but I'm wondering if there is any way to check when a file is read by another application.

Example: I have the file C:\test.txt on my harddrive and am watching it using FileSystemWatcher. Another program (not under my control) goes to read that file; I would like to catch that event and, if possible, check what program is reading the file then modify the contents of the file accordingly.

+1  A: 

A little snippet that I found useful for detecting when another process has a lock:

 static bool IsFileUsedbyAnotherProcess(string filename) 
        { 
            try 
            { 
                File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None); 
            } 
            catch (System.IO.IOException exp) 
            { 
                return true; 
            } 
            return false; 
        }
John M
Only works if the other application has locked it for writing. Opening a file to read doesn't necessarily lock it.
KeithS
Egad! That function leaves the file open until it gets garbage-collected, meaning that nobody else can open it without sharing enabled.
Gabe
And who closes the File.Open() here?
kofucii
+1  A: 

You could use FileInfo.LastAccessTime and FileInfo.Refresh() in a polling loop.

http://msdn.microsoft.com/en-us/library/system.io.fileinfo_members.aspx

Jonathan S.
+3  A: 

The easiest way I can think of to do this would be with a timer (System.Threading.Timer) whose callback checks and stores the last

System.IO.File.GetLastAccessTime(path)

Something like (maybe with a bit more locking...)

public class FileAccessWatcher
{

public Dictionary<string, DateTime> _trackedFiles = new Dictionary<string, DateTime>();

private Timer _timer;

public event EventHandler<EventArgs<string>> FileAccessed = delegate { };

public FileAccessWatcher()
{
    _timer = new Timer(OnTimerTick, null, 500, Timeout.Infinite);
}

public void Watch(string path)
{
    _trackedFiles[path] = File.GetLastAccessTime(path);
}

public void OnTimerTick(object state)
{
    foreach (var pair in _trackedFiles.ToList())
    {
        var accessed = File.GetLastAccessTime(pair.Key);
        if (pair.Value != accessed)
        {
            _trackedFiles[pair.Key] = accessed;
            FileAccessed(this, new EventArgs<string>(pair.Key));
        }
    }

    _timer.Change(500, Timeout.Infinite);
}
}
JeffN825
+1  A: 

There is SysInternals' program FileMon... It can trace every file access in the system. If you can find its source, and understand what win32 hooks it uses, you might marshal those functions in C# and get what you want.

alxx
+1  A: 

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.

KeithS
A: 

Yes, using file system filter driver you can catch all read requests, analyze them and even substitute the data being read. Development of such driver yourself is possible, but very time-consuming and complicated. We offer a product called CallbackFilter, which includes a ready to use driver and lets you implement your filtering business logic in user-mode.

Eugene Mayevski 'EldoS Corp