Search code examples
c#timerfilesystemszipfilesystemwatcher

Repeating a method call on each direcotry with timer elasped in C#


Overview:

I've created two FileSystemWatcher to detect sub-folders and its files creation. I also use a Timer to the second watcher(file watcher), which restart the timer for every file created to any of each folder before calling a zip method dynamically.

I try to make this process to every folder, but it zips all folder at once regardless if there is a file moving into those folders.

Below is part of my code to simulate the timer and zip process... I might have a problem moving the zip file to root folder when calling the zip method.

The Timer inside the file Watcher

namespace ZipperAndWatcher
{
    public class Archive
    {
        public void CreateZip(string path)
        {    
          // zip method code
        }

    }

    public class FileWatcher
    {
        private FileSystemWatcher _fsw;
        private Archive _zip;
        private string _path;
        private Timer _timer;

        public FileWatcher()
        {
            _fsw = new FileSystemWatcher();
            _zip = new Archive();

            _path = @"D:\Documents\output";
            _timer = new Timer();
        }

        public void StartWatching()
        {
            var rootWatcher = _fsw;
            rootWatcher.Path = _path;
            rootWatcher.Created += new FileSystemEventHandler(OnRootFolderCreated);
            rootWatcher.EnableRaisingEvents = true;
            rootWatcher.Filter = "*.*";
        }

        private void OnRootFolderCreated(object sender, FileSystemEventArgs e)
        {
            string watchedPath = e.FullPath; // watched path

            // create another watcher for file creation and send event to timer
            FileSystemWatcher subFolderWatcher = new FileSystemWatcher();
            subFolderWatcher.Path = watchedPath + @"\";

            // Timer setting
            var aTimer = _timer;
            aTimer.Interval = 20000;

            // Lambda == args => expression
            // send event to subFolderWatcher
            aTimer.Elapsed += new ElapsedEventHandler((subfolderSender, evt) => OnTimedEvent(subfolderSender, evt, subFolderWatcher));
            aTimer.AutoReset = false;
            aTimer.Enabled = true;

            // sub-folder sends event to timer (and wait timer to notify subfolder)
            subFolderWatcher.Created += new FileSystemEventHandler((s, evt) => subFolderWatcher_Created(s, evt, aTimer));
            subFolderWatcher.Filter = "*.*";
            subFolderWatcher.EnableRaisingEvents = true;
        }

        private void OnTimedEvent(object sender, ElapsedEventArgs evt, FileSystemWatcher subFolderWatcher)
        {
            subFolderWatcher.EnableRaisingEvents = false;

            // Explicit Casting
            Timer timer = sender as Timer;
            timer.Stop();
            timer.Dispose();

            // Once time elapsed, zip the folder here?
            Console.WriteLine($"time up. zip process at {evt.SignalTime}");               
            Archive zip = _zip;
            zip.CreateZip(subFolderWatcher.Path.Substring(0, subFolderWatcher.Path.LastIndexOf(@"\")));

            subFolderWatcher.Dispose();
        }

        private void subFolderWatcher_Created(object sender, FileSystemEventArgs evt, Timer aTimer)
        {
            // if new file created, stop the timer
            //  then restart the timer
            aTimer.AutoReset = false;
            aTimer.Stop();
            aTimer.Start();
            Console.WriteLine($"restart the timer as {evt.Name} created on {DateTime.Now.ToString()}");
        }
    }
}

Solution

  • You wrote in your last comment: "what I want is to only zip the specific subdirectories, which has no more files being added after the time elapsed while other subdirectories might still have files adding in, and it is not ready to be zipped"

    So in your timer handler (OnTimedEvent), you need to pass the path to the directory that is ready for zipping to CreateZip, not the parent directory, i.e. change

    zip.CreateZip(subFolderWatcher.Path.Substring(0, subFolderWatcher.Path.LastIndexOf(@"\")));
    

    to

    zip.CreateZip(subFolderWatcher.Path);
    

    Then in your CreateZip method just zip the directory that is passed as parameter, not all subdirectories as you do now.