10

I have a program that roughly does this:

  1. open a file to read from it.
  2. close the file
  3. Start a filewatcher to watch for changes in the file.
  4. As soon as a change is detected, the filewatcher's EnableRaisingEvents flag is set to false and the process repeats from Step 1.

The problem is, after going from step 4 to step 1, it cannot read the file saying that it is being used by another Process.

Error I receive:

Unhandled Exception: System.IO.IOException: The process cannot access the file 'c:\test.xml' because it is being used by another process.

Whats going wrong? does the reader from Step 1 of my program still have the file open, or is some entirely different process accessing the file, or is it that filewatcher is still watching the file after moving to Step 1 from 4, despite setting the flag to false?

Ayush
  • 41,754
  • 51
  • 164
  • 239

7 Answers7

9

If your code is similar to this:

[STAThread]
static void Main(string[] args)
{
    string file = "temp.txt";
    ReadFile(file);
    FileSystemWatcher fswatcher = new FileSystemWatcher(".\\");
    fswatcher.Changed += delegate(object sender, FileSystemEventArgs e)
                             {
                                 ReadFile(e.FullPath);
                             };
    while (true)
    {
        fswatcher.WaitForChanged(WatcherChangeTypes.Changed);
    }
}
private static void ReadFile(string file)
{
    Stream stream = File.OpenRead(file);
    StreamReader streamReader = new StreamReader(stream);
    string str = streamReader.ReadToEnd();
    MessageBox.Show(str);
    streamReader.Close();
    stream.Close();
}

If you are editing the file via notepad, then, when you click the save button, it keeps the file open, while as if when you just close the program and click save it doesn't. I do no know if this is a bug or an undocumented feature of notepad, but this just might be your problem. One way to fix this is to do the following:

In your anonymous delegate, or wherever you execute the call to ReadFile() call Thread.Sleep(1000), to have the program wait before reading the file and your code should work fine.

Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
  • @xbonez: this code works fine for me, even without `Thread.Sleep()`. (I changed `MessageBox.Show` to `Console.WriteLine`) However, I would still use a `using` statement. – JohnB Sep 17 '10 at 18:06
  • After playing around some more, I found out that if I have two instances of this program watching the same file, when I click "Save" in Notepad, I get this error from one of the instances (the other continues to run): `The process cannot access the file 'c:\file.txt' because it is being used by another process.` – JohnB Sep 17 '10 at 18:44
  • Upon further messing around, I got `The process cannot access the file` error sometimes even with only one copy of the watcher program running. Therefore, I put `Thread.Sleep(500)` in the `delegate` before `ReadFile(e.FullPath)` and it works great now. I have a robust little file watcher program now: +1 Richard :) – JohnB Sep 17 '10 at 19:52
4

You can use a tool like Process Explorer from http://www.sysinternals.com to see who has the open handle to the process

The file is most likely held open by whatever caused the change notification to fire in the first place.

Michael
  • 54,279
  • 5
  • 125
  • 144
3

Note: even if "file.txt" is open in Notepad, this code still works, because it is opening for read.

using System;
using System.IO;

class Program
{
  static void Main(string[] args)
  {
    ReadFromFile(@"C:\file.txt");
    Console.ReadLine();
  }

  static void ReadFromFile(string filename)
  {
    string line;
    using (StreamReader sr = File.OpenText(filename))
    {
      line  = sr.ReadLine();
      while (line != null)
      {
        Console.WriteLine(str);
        line = sr.ReadLine();
      }
      sr.Close();
    }
  }
}

Or just:

string text = System.IO.File.ReadAllText(@"C:\file.txt");

JohnB
  • 18,046
  • 16
  • 98
  • 110
3

Beside other answers it is possible that when FileWatcher reacts file it not yet closed by that app. In step 1 try not to fail immediately but try several attempts with small delay.

Andrey
  • 59,039
  • 12
  • 119
  • 163
1

The problem is that the FileSystemWatcher tells you immediately when the file was created. It doesn't wait for the file to be released. For instance, when you copy a large file which takes 3 seconds to copy, so you have to open the file after that.

http://www.codeproject.com/Questions/461666/FileSystemWatcher-issue-in-windows-application Wait until file is unlocked in .NET

Community
  • 1
  • 1
Shahab J
  • 1,363
  • 11
  • 10
0

There are a number of things that could be going on.

First, make sure you properly dispose of the file writer (close isn't good enough) by utilizing the using clause around everything that implements IDisposable.

Second, it you are simply reading, make sure you have the correct flags set when opening the file.

To go any further it would help if you provided a code block which showed how you were accomplishing this; particularly around the reading of the file

NotMe
  • 87,343
  • 27
  • 171
  • 245
0

You can use this MS utility openfiles to obtain list of opened files and understand who has opened the file.

openfiles /query

Also it allow to disconnect files opened by network users.

openfiles /disconnect /id XXXX

If you want use it for local PC you should set Maintain Objects List global flag:

openfiles /local on

Follow the link to get more details.

alexber
  • 647
  • 1
  • 5
  • 9