Search code examples
c#filefilesystemwatcher

Why am I getting a Unhandled Exception: System.IO.IOException when trying to read from a file being written to?


I have two C# applications, one is reading a file (File A) line by line and writing its contents to a different file (File B).

The second application is using FileSystemWatcher for File B to see when it is updated and reporting the difference is line numbers between when the program was started and when the file was changed.

Thats all I am trying to do for now, ultimately I want to read the lines between when the file was last read and the current read but until I can get the line difference that is on hold.

The code that I have for application 1 is;

        static void Main(string[] args)
    {
        String line;

        StreamReader sr = new StreamReader("f:\\watch\\input.txt");

        FileStream fs = new FileStream("f:\\watch\\Chat.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
        StreamWriter sw = new StreamWriter(fs);

        while ((line = sr.ReadLine()) != null)
        {
            sw.WriteLine(line);
            Thread.Sleep(200);
            Console.WriteLine(line);
            sw.Flush();

        }

        sw.Close();
        sr.Close();

    }

The code that I have for application 2 is;

        public static int lines = 0;

    public static void Main()
    {
        Run();
    }

    public static void Run()
    {
        string[] args = System.Environment.GetCommandLineArgs();

        if (args.Length != 2)
        {
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
   | NotifyFilters.FileName | NotifyFilters.DirectoryName;

watcher.Filter = "Chat.log";

watcher.Changed += new FileSystemEventHandler(OnChanged);

watcher.EnableRaisingEvents = true;

lines = File.ReadAllLines(args[1] + "\\Chat.log").Length;

Console.WriteLine("File lines: " + lines);

while(Console.Read()!='q');
}

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

public static string Linework(string path)

{



   string newstring = " ";

using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    int newlines = File.ReadAllLines(path).Length;
    Console.WriteLine("Lines now: " + newlines);
}

return newstring;

}

Now when I try and run these two applications together I get an exception saying "Unhandled Exception: System.IO.IOException: The process cannot access the file because it is in use by another process".

I have both filestreams setup for ReadWrite access and I have one of the filestreams setup for FileAccess.Write and the other for FileAccess.Read.

Any clues as to why I would be getting this exception?

Thanks Hew.


Solution

  • lines = File.ReadAllLines(args[1] + "\Chat.log").Length;

    There's your problem. That method opens the file, reads all the lines and closes it again. It uses "normal" file share settings when opening the file, FileShare.Read. That denies write access to any other process that also has the file opened.

    That cannot work here, you've already have the file opened with write access. The 2nd process cannot deny it. The IOException is the result.

    You cannot use File.ReadAllLines() as-is here, you need to open a FileStream with FileShare.ReadWrite, pass it to a StreamReader and read all lines.

    Beware the very troublesome race potential you've got here, there's no guarantee that the last line you'll read is a complete line. Getting only a \r and not the \n at the end of the line is a particularly tricky issue. This will strike randomly and infrequently, the hardest bugs to troubleshoot. Maybe your Flush() call fixes it, I've never been brave enough to put this to the test.