none
How to have your timer1 pause for 20 seconds then carry on c# RRS feed

  • Question

  • Hi, I am reading through a directory every 30 seconds and reading any files that are in this directory.

    So on timer1_Tick, I foreach through a directory using DirectoryInfo, the timer is set to thirty seconds, after it has processed the first file I would like it to pause for 20 seconds before reading the next file. How can I do this? 

    Here is my code:

    private void timer1_Tick( object sender , EventArgs e )
    {
       DirectoryInfo	dirInfo		= new DirectoryInfo ( 
       _dirName );
       
       foreach ( var Filein dirInfo.GetFiles ( ) )
    	{
              if ( pFileLength > 0 )
    	  {
    	    using ( var stream = pFile.OpenRead ( ) )
    	    {
    		using ( var reader = new StreamReader ( 
                    stream ) )
    		{
    		string line;
    		while ( ( line = reader.ReadLine ( ) ) != 
                    null )
    		{
    		
    		if ( line.Contains("Director")( line ) )						 
                    wantedData.Add ( line );
    		}
    	     }
    	   }
    	}
     

    At the end of the foreach I would like to pause for 20 seconds, do I add another timer? if so how and where or can I pause the timer1 for 20 seconds then loop through the next file?

    Thanks for your help.


    CuriousCoder

    Thursday, April 12, 2018 10:15 AM

Answers

  • UPDATE: Reread your question and realized you wanted to pause between file reads instead of the polling process. Please clarify why you would read the directory and then pause between each file read (since the directory contents could change during the 20 second interval).

    Why are you polling a directory structure? Have you considered looking at using FileSystemWatcher which eliminates the need for polling and is going to be more efficient in terms of resources needed?

    When working with timers be sure to clarify which one you're using. The core library has 2 timer classes, each UI framework adds another timer.

    System.Threading.Timer

    System.Timers.Timer

    System.Windows.Forms.Timer

    Since you are receiving an EventArgs argument it appears you're using the Windows Forms version. It is critically important to note that because you're using this version that the event is occurring on the UI thread. Therefore any work you do on this thread will stall the UI. Don't make blocking calls here otherwise your UI will stall.

    To pause a timer you just stop or disable it (depending upon the timer you're using). start it again when you're done. 20 seconds doesn't indicate whether that is after you've done your polling or not. Here's how I'd do it (if I weren't using FileSystemWatcher) on a Winforms timer.

    //When setting up your timer set the interval to the delay you want
    timer1.Interval = 20000; //20 seconds
    
    //In tick handler
    timer1.Stop();
    
    //Do your work
    
    //Start the timer over again
    timer1.Start();


    Michael Taylor http://www.michaeltaylorp3.net


    Thursday, April 12, 2018 2:09 PM
    Moderator
  • Hello CuriousCoder15,

    Or you use async/await keyword to set 20s seconds without blocking UI thread. Simple code like below.

            private async void button1_Click(object sender, EventArgs e)
            {
                string _dirName = @"D:\Test";
    
                DirectoryInfo dirInfo = new DirectoryInfo(_dirName);
    
                foreach (var File in dirInfo.GetFiles())
                {
                    ...
                    //when file finish operating, run the below code will pause 20s without blocking
                    await Task.Delay(20000);           
                }
            }

    Best Regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, April 13, 2018 5:57 AM
    Moderator

All replies

  • Hi!

    In my opinion having a two timers is good solution. You also can create an enumeration for describe a current state or use a boolean value and use only one timer, but it will be little bit overcomplicated. I would like to suggest you use a Queue to store FileInfo for the Tick handlers.

    public partial class Form1 : Form { private Timer directoryTimer = new Timer(); private Timer fileTimer = new Timer(); private string _dirName = @"d:\MyDirectory"; private Queue<FileInfo> files = new Queue<FileInfo>(); public Form1() { fileTimer.Interval = 20_000; fileTimer.Tick += FileTimer_Tick; directoryTimer.Interval = 30_000; directoryTimer.Tick += DirectoryTimer_Tick; directoryTimer.Start(); } private void FileTimer_Tick(object sender, EventArgs e) { if (files.Count == 0) { fileTimer.Stop(); directoryTimer.Start();

    return; } var file = files.Dequeue(); // do something with file info } private void DirectoryTimer_Tick(object sender, EventArgs e) { DirectoryInfo dirInfo = new DirectoryInfo(_dirName); // collect all files to the temporary structure foreach (var file in dirInfo.GetFiles()) files.Enqueue(file); directoryTimer.Stop(); fileTimer.Start(); } }




    Thursday, April 12, 2018 10:41 AM
  • Hi, thanks, I'm just trying to understand how it works and how to use it in my program. I will let you know when I finish.

    Thanks


    CuriousCoder

    Thursday, April 12, 2018 12:47 PM
  • UPDATE: Reread your question and realized you wanted to pause between file reads instead of the polling process. Please clarify why you would read the directory and then pause between each file read (since the directory contents could change during the 20 second interval).

    Why are you polling a directory structure? Have you considered looking at using FileSystemWatcher which eliminates the need for polling and is going to be more efficient in terms of resources needed?

    When working with timers be sure to clarify which one you're using. The core library has 2 timer classes, each UI framework adds another timer.

    System.Threading.Timer

    System.Timers.Timer

    System.Windows.Forms.Timer

    Since you are receiving an EventArgs argument it appears you're using the Windows Forms version. It is critically important to note that because you're using this version that the event is occurring on the UI thread. Therefore any work you do on this thread will stall the UI. Don't make blocking calls here otherwise your UI will stall.

    To pause a timer you just stop or disable it (depending upon the timer you're using). start it again when you're done. 20 seconds doesn't indicate whether that is after you've done your polling or not. Here's how I'd do it (if I weren't using FileSystemWatcher) on a Winforms timer.

    //When setting up your timer set the interval to the delay you want
    timer1.Interval = 20000; //20 seconds
    
    //In tick handler
    timer1.Stop();
    
    //Do your work
    
    //Start the timer over again
    timer1.Start();


    Michael Taylor http://www.michaeltaylorp3.net


    Thursday, April 12, 2018 2:09 PM
    Moderator
  • Hello CuriousCoder15,

    Or you use async/await keyword to set 20s seconds without blocking UI thread. Simple code like below.

            private async void button1_Click(object sender, EventArgs e)
            {
                string _dirName = @"D:\Test";
    
                DirectoryInfo dirInfo = new DirectoryInfo(_dirName);
    
                foreach (var File in dirInfo.GetFiles())
                {
                    ...
                    //when file finish operating, run the below code will pause 20s without blocking
                    await Task.Delay(20000);           
                }
            }

    Best Regards,

    Neil Hu


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, April 13, 2018 5:57 AM
    Moderator
  • Thank you for your comments, I am just learning to program so wasn't aware there were so many timer classes, noted for next time.

    I am polling a directory because I want to take the info from the files that arrive there and upload them to the database if more than one file arrives in the folder at the same time then the process slows and I was worried about occupying my DB for too long so I wanted to ensure that there would be a break after reading each file. All file names once read are also added to my DB, when I loop through the folder again I check with my DB to see if I have already looked at the file in the folder, if not then process it. So I never miss a file but as far as I know with the fileWatcher class it is possible to miss a file if more than one file arrives at the same time. I may be wrong but I am learning. Hope that provides a little more context.

    Thanks again 


    CuriousCoder

    Friday, April 13, 2018 7:45 AM
  • " if more than one file arrives in the folder at the same time then the process slows and I was worried about occupying my DB for too long"

    Databases can handle 100s or 1000s of transactions a second, depending on the DB, server, etc. You aren't going to slow down your DB unless you're doing something crazy like running queries that take seconds to run. Don't put arbitrary slowdowns in your code for that.

    "but as far as I know with the fileWatcher class it is possible to miss a file"

    FSW isn't going to miss file updates except for in extreme error cases. It is actually going to be far more accurate than your code. Your code won't detect new files for a long time compared to FSW which will notify you immediately. 

    The reason people run into issues with the FSW is that they write code that takes too long to execute and the notification buffer fills up. FSW is called from the file system directly via the Journaling API. Since this is happening as IO is occurring it has to be fast. The correct solution for working with FSW is to add the notification information to a queue and then have a background process do the actual heavy lifting. You'll never miss a notification at that point. Note however that you can (and will) get multiple events for the same file so you need to handle that. But you're already going to have that situation with your existing code anyway.

    There are many good articles on how to use FSW properly. Here's one I wrote years ago. It is old but the code is still the same. I would use this over a timer always. There is no real reason for a timer in this type of situation.


    Michael Taylor http://www.michaeltaylorp3.net

    Friday, April 13, 2018 1:48 PM
    Moderator
  • I will read through your article and practice with the watcher class, thank you for the link.

    Kind Regards

     

    CuriousCoder

    Monday, April 16, 2018 8:45 AM