1

I wrote program and need my own file watcher (loop that checks if file can be opened). Something like this:

while (loadedFiles.Count > 0 || isNeedReRead)
{
    Thread.Sleep(1000);
    if (isNeedReRead)
        ReadFromRegistry();

    foreach (var file in loadedFiles)
    {
        if (!IsFileLocked(file.Value))
        {
              // logic
        }
    }
}

Source: Is there a way to check if a file is in use?

Here is my solution:

try
{
    using (Stream stream = new FileStream(
        path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
    {
        stream.Close();
        return false;
    }
}
catch (IOException)
{
    return true;
}

It works fine with Word, Excel. But if the process does not lock the file, this method doesn't help. For example if an open bitmap file is changing, IsFileLocked returns false.

Any ideas?

Community
  • 1
  • 1
Maksym
  • 244
  • 1
  • 2
  • 18
  • Would being notified if the file changes be acceptable? If so you can use the System.IO.FileSystemWatcher class. – Matt Johnson May 23 '13 at 17:58
  • What would this be useful for? Even if you check that the file can be opened, there's no guarantee that it can still be opened when you actually try to open it, even if it's the very next line of code. You still have to wrap your file access in a `try-catch`. – JosephHirn May 23 '13 at 18:09
  • I can't use FileSystemWatcher. It notifies when file is changed. I need OnClosed notification. My program contains some files. And when I open some of them, my watcher begin run. When file is closed, watcher updates it, if need. But i can close program before close file. In that case, watcher starts when program loaded and checks all previously opened files. If this file not opened, then it updated. – Maksym May 23 '13 at 18:11

1 Answers1

2

You can setup monitoring the file by using the System.IO.FileSystemWatcher you should be able to use that the NotifyFilter property (set to LastAccessTime) to detect when a particular file was last accessed.

void SetupWatcher()
{
    // Create a new FileSystemWatcher and set its properties.
        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = @"C:\";
    /* Watch for changes in LastAccess and LastWrite times, and
       the renaming of files or directories. */
    watcher.NotifyFilter = NotifyFilters.LastAccess;

    // Only watch text files.
    watcher.Filter = "*.txt";

    // Add event handlers.
    watcher.Changed += new FileSystemEventHandler(OnChanged);
    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.Deleted += new FileSystemEventHandler(OnChanged);
    watcher.Renamed += new RenamedEventHandler(OnRenamed);

        // Begin watching.
        watcher.EnableRaisingEvents = true;
}

// Define the event handlers. 
    private static void OnChanged(object source, FileSystemEventArgs e)
    {
        // Specify what is done when a file is changed, created, or deleted.
       Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
    }

private static void OnRenamed(object source, RenamedEventArgs e)
{
    // Specify what is done when a file is renamed.
    Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath);
}

Another option assuming this is windows is to enumerate the list of open file handles for each process. The code posted here has a decent implementation so all you have to do is call

DetectOpenFiles.GetOpenFilesEnumerator(processID);

However, if a process opens a file reads the contents into memory then closes the file, you will be stuck with the monitoring option (listed above), since the process does not actually have the file open any longer once it is read into memory.

Matt Johnson
  • 1,913
  • 16
  • 23