2 Filesystem Watchers or Get out of loop in 1 watcher

Mimoa

Member
Joined
Apr 29, 2020
Messages
24
Programming Experience
1-3
Hello.
I have a simple simulator - it starts a Filesystem watcher and watch one directory for new files. The file comes and when it has the right name, watcher runs function. This function is loop Do-While and it generates files for other program (the one that create the first file...). Now, everything is fine - file comes, watcher runs function and it generates file for each 5 seconds. OK.
Now I need either another watcher to watch over another file in the same directory or I need to start the function for file generation but outside of the watcher to make the watcher free to watch again the directory over.
How can it be done?
When I choose 2 watchers - they will collide, when the file is created in watched folder.


C#:
        public void FileWatcher()   // watches BaseDir = folder s programem *.exe
        {
            WatcherON = true;
            if (File.Exists("Status.JOB")) { File.Delete("Status.JOB"); }
            if (File.Exists("Cykly.JOB")) { File.Delete("Cykly.JOB"); }
            Watcher = new FileSystemWatcher();
            Watcher.Path = AppDomain.CurrentDomain.BaseDirectory;
            Watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.LastAccess | NotifyFilters.LastWrite;
            Watcher.Filter = "*.JOB";                                                           
            Watcher.Created += new FileSystemEventHandler(FChange);
            Watcher.EnableRaisingEvents = true;
        }
        public void FChange(object source, FileSystemEventArgs e)
        {
            Thread.Sleep(200);
            string strFile = e.Name;


            if (strFile == "Cykly.JOB" && LBINFO.Text == "AUTOMAT")
            {
                Thread.Sleep(200);
                if (File.Exists("Cykly.JOB")) { File.Delete("Cykly.JOB"); }
                if (File.Exists("Cykly.dat")) { File.Delete("Cykly.dat"); }
                do
                {
                    if (File.Exists("Cykly.dat")) { File.Delete("Cykly.dat"); }
                    using (StreamWriter PDVF = File.CreateText("Cykly.dat"))
                    {
                        Random Rand = new Random();
                        PDVF.WriteLine("NUR");
                        PDVF.WriteLine(Rand.Next(0, 100000));
                        PDVF.Close();
                        Thread.Sleep(5000);
                    }
                }
                while (generate);
                try
                {
                    using (FileStream PDVF = File.OpenRead("Cykly.dat"))
                    {
                        PDVF.Close();
                    }
                }
                catch { }
            }


            if (strFile == "Status.JOB")
            {
                using (StreamWriter PDVF = File.CreateText("Status.dat"))
                {
                  
                    PDVF.WriteLine("NUR");
                    if (LBINFO.Text =="AUTOMAT") PDVF.WriteLine("0A");
                    if (LBINFO.Text == "RUCNI") PDVF.WriteLine("0M");
                    if (LBINFO.Text == "SERIZOVANI") PDVF.WriteLine("0U");
                    PDVF.Close();
                }

            }
        }
 
Given that a FileSystemWatcher raises its events on a secondary thread by default, I wouldn't have thought that there would be an issue with multiple event handlers running at the same time. They should just run on different threads.
 
No, it is stuck in
C#:
if (File.Exists("Cykly.dat")) { File.Delete("Cykly.dat"); }
                    using (StreamWriter PDVF = File.CreateText("Cykly.dat"))
                    {
                        Random Rand = new Random();
                        PDVF.WriteLine("NUR");
                        PDVF.WriteLine(Rand.Next(0, 100000));
                        PDVF.Close();
                        Thread.Sleep(5000);
                    }
                }

which works fine, but no watching anymore.
 
No, it is stuck in
C#:
if (File.Exists("Cykly.dat")) { File.Delete("Cykly.dat"); }
                    using (StreamWriter PDVF = File.CreateText("Cykly.dat"))
                    {
                        Random Rand = new Random();
                        PDVF.WriteLine("NUR");
                        PDVF.WriteLine(Rand.Next(0, 100000));
                        PDVF.Close();
                        Thread.Sleep(5000);
                    }
                }

which works fine, but no watching anymore.
There's a bit wrong there. Firstly, the whole point of a using block is to dispose/close objects automatically, so closing your writer inside that using block defeats the point. Secondly, checking for the file and deleting it is pointless when you can just overwrite it:
C#:
File.WriteAllLines("Cykly.dat", new object[] {"NUR", new Random().Next(0, 100000)});
You really ought to create one Random object and reuse it though, rather than creating a new one every time.
 
I have to close the stream inside using because other program should manipulate with the created file and there would be collision. The same for deleting - I have to delete the file and create another one because the watcher in other program watches if the file was created. Of course I can change the filter to created + changed. This is not important for me now. I need the watcher to work properly.
 
I have to close the stream inside using because other program should manipulate with the created file and there would be collision.
Yes it is true that you have to close the stream so that the other program can work on it. What we are saying is that you don't have to explicity call Close(). When the using block ends, the compiler will insert code to dispose the stream and the stream will be closed i in the process of being disposed.

In other words, this:
C#:
using (StreamWriter PDVF = File.CreateText("Cykly.dat"))
{
    Random Rand = new Random();
    PDVF.WriteLine("NUR");
    PDVF.WriteLine(Rand.Next(0, 100000));
    PDVF.Close();
    Thread.Sleep(5000);
}

can be re-written as:
C#:
using (StreamWriter PDVF = File.CreateText("Cykly.dat"))
{
    Random Rand = new Random();
    PDVF.WriteLine("NUR");
    PDVF.WriteLine(Rand.Next(0, 100000));
}
Thread.Sleep(5000);
 
which works fine, but no watching anymore.
Unless Microsoft broke something in newer version of the .NET Framework, in my experience with the .NET Framework 2 through 4.8 is that the file watcher continues to work even after files are deleted and created within the watched directory. The only time I ran into weird behaviors were:
  • Directory being watched was on a network drive/share
  • McAfee (and other anti-virus) doing file scans on newly created files
 
Yes it is true that you have to close the stream so that the other program can work on it. What we are saying is that you don't have to explicity call Close(). When the using block ends, the compiler will insert code to dispose the stream and the stream will be closed i in the process of being disposed.


Oh I see now. Thanks. But the watcher catches anything new in the diretory, when the first catch is made - it generates the file as it should, but watcher do not watches for another changes in folder - how can I check, what is wrong?
 
From what I can see from the code posted in post #1, you are stuck in an infinite loop on lines 24-36. Since that infinite loop is running on the same threadpool thread that is watching for changes and fires off the events, then that thread never gets back around to watching again.
 
From what I can see from the code posted in post #1, you are stuck in an infinite loop on lines 24-36. Since that infinite loop is running on the same threadpool thread that is watching for changes and fires off the events, then that thread never gets back around to watching again.
Yes, that is, what I meant in the first post - so how to get out of the thread with this infinite loop (meaning it should stay looping ) and free the thread for the watcher again OR how to start 2 watchers but tell to one of them, that the other one is primary and you shoud start after the first one is watching = some trigger in the primary one?
 
Do the looping on another thread.

I still don't understand why you would want to do this, though. If the detection of a "Cykly.JOB" is the flag to create just one "Cykly.DAT" file. Then just create one and be done. On the other hand, if detection of a "Cykly.JOB" is supposed to create an infinite number of "Cykly.DAT" files, then spin up another thread or use the thread pool and enque work items there.
 
It is a simulation program p1 for another work program p2. Normaly the p2 communicates with the Euromap63 interface on injection machines - you send the job info file to the machine (and you tell the machine to send process data each cycle. It generates another file with process data - you take the data...) Now EU63 is more sophisticated and sure it has more threads for work. I need to make tiny simulation of this interface just for presentation. There I need the cykly.dat continuous generation BUT, moreover I have a button in GUI of p2 to check the status of the machine - another status.JOB file - machine will take it and send another status.DAT file with info of the machine state - auto, manual, set, power off. So watcher must work after cykly.JOB is detected. I thought of the simple solution - lets make another watcher and communicate with the p1 program via subfolder - it would work- but its way too easy. It is time to learn about threads. When I tried to learn it in the past, it was quite complicated and sure it still is....for me.
 
I didn't originally notice all the sleeps you have in your notification handler and in in your infinite loop. Take a look at using a timer instead of another thread. Depending on which flavor of .NET's 4 (or is it 5?) different kinds of timers you'll either have the timer elapsed event running on your UI thread or in a thread pool thread. But regardless of which thread it is, it'll help you get into the mindset of just doing one or two quick operations when you are notified of the timer tick and then you just wait for the timer to fire again later.
 
Those 200msec sleeps are not necessary or needed at all. It was delay for p2 to have time to close the generated file before p1 opens it. Now we just take the file name so without delay it is OK too.
Could you please provide some documentation or example of what you mean by this timer? Timer itself is the same as cyclic interrupted (..rruptuated... I dont know the word.. many time interrupted/still interrupting...) delay, or isnt? It is .NET 4.8 but I can go higher.
From what you have written, I understand that there is inbuilt timer, which ticks in the background, the thread is free and just in some defined (...timed) moment, it executes some block of code? ...while thread, in which it was started is free all the time since then (except the block execution)
Tht would be very good for me.
 
Here's something to get you started in your research:
 
Solution
Back
Top Bottom